def initialize(): context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='tty') observer = MonitorObserver(monitor, callback=print_device_event, name = 'monitor-observer') observer.daemon observer.start()
class Udev(QObject): def __init__(self): super(Udev, self).__init__() def monitor_async(self, subsystems, device_type, callbak): context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystems) def device_event(device): self.emit(SIGNAL("signal_udev"), device) if callbak != None: callbak(device) try: self.observer = MonitorObserver(monitor, callback=device_event, name='udev-monitor-observer') self.observer.daemon self.observer.start() #observer.stop() except Exception as e: LogRecord.instance().logger.info(u'USB监听启动异常(%s)'%(str(e))) def monitorStop(self): try: self.observer.stop() except Exception as e: pass
class Listener(object): def __init__(self): self.context = Context() self.monitor = Monitor.from_netlink(self.context) self.monitor.filter_by(subsystem='usb') self.observer = MonitorObserver( self.monitor, callback=self.event_handler, name="blahblah") self.observer.daemon = True def start_listening(self): self.observer.start() def event_handler(self, device): d = {k: device[k] for k in device} if 'ID_VENDOR_ID' not in d or 'ACTION' not in d: return if d['ID_VENDOR_ID'] not in vendor_ids: return sleep(2) # Give the drive time to mount self.device_state_changed(d['ACTION']) def device_state_changed(self, action): raise NotImplementedError
def watch(self, filtername, callback): context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(filtername) observer = MonitorObserver(monitor, callback=callback, name="monitor-observer") observer.start()
def start_udev_monitoring(): #Setting up Linux UDEV monitoring in a separate thread context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='block') observer = MonitorObserver(monitor, callback=find_garmin, name='monitor-observer') observer.daemon = True observer.start()
def monitor_background(): c = Context() monitor = Monitor.from_netlink(c) monitor.filter_by("block", "disk") obs = MonitorObserver(monitor, device_event) obs.start()
def set_monitor_func(func): global HANDLER HANDLER = func udev_context = Context() monitor = Monitor.from_netlink(udev_context) monitor.filter_by('block') observer = MonitorObserver(monitor, log_event) observer.start()
def start(self): self.observer = MonitorObserver(self.monitor, callback = self.start_monitor, name='monitor-usb-inhibitor') # For the lock screen (the usb inhibit will continue to run until # a signal is received -- that would tell the screen unlocked) # Form the dict with the known devices if self.flag_known_devices: self.get_known_devices() # Initial devices not formed - currently not used #self.form_initial_devices() with open('/sys/bus/usb/drivers_autoprobe', 'wt') as f_out: f_out.write("0") print("Start monitoring!") if not self.running_mode_cont: proc = self.start_process() print ("Runs with a given command mode") self.observer.start() while proc.poll() is None: continue # For continuous mode must be called manually the stop command else: # For testing purposes one can let False and then run the inhibit # in continuous mode to see the output of it self.observer.daemon = False self.observer.start() print("Runs in continuous mode")
def __init__(self): self.context = Context() self.monitor = Monitor.from_netlink(self.context) self.monitor.filter_by(subsystem='usb') self.observer = MonitorObserver( self.monitor, callback=self.event_handler, name="blahblah") self.observer.daemon = True
def __init__(self, add_callback, remove_callback = None, change_callback = None, for_gui = False): self._logger = logging.getLogger('efalive.UsbStorageMonitor') self._external_add_callback = add_callback self._external_remove_callback = remove_callback self._external_change_callback = change_callback self._udev_context = Context() self._udev_monitor = Monitor.from_netlink(self._udev_context) self._udev_monitor.filter_by('block', device_type='partition') self._for_gui = for_gui if for_gui: self._udev_observer = UdevGuiObserver(self._udev_monitor) self._udev_observer.connect('device-event', self._handle_gui_device_event) else: self._udev_observer = UdevObserver(self._udev_monitor, callback=self._handle_device_event, name='monitor-observer')
class UdevManager(object): """Manger mixin that takes care of udev event handling.""" def __init__(self): # Create connection to udev. self.udev = Context() def start_udev_tasks(self): """Start monitoring system devices using udev.""" def udev_handler(action, device): if device.subsystem in ('net', 'block'): self.raise_event((action, device.subsystem), device) self.raise_event((action, device.subsystem, device.sys_name), device) # Monitor interesting system events. self.monitor = Monitor.from_netlink(self.udev) self.observer = MonitorObserver(self.monitor, from_thread(udev_handler)) self.observer.start() # Trigger missed events. reactor.callLater(0, self.raise_missed_udev_events) def raise_missed_udev_events(self): """ Raise events for all present net and block devices. This is intended to be executed right after we subscribe to regular udev event notifications to get up to speed with current state of the system. Raised events are: ('add', subsystem) -> device ('add', subsystem, sys_name) -> device """ for subsystem in ('net', 'block'): for device in self.udev.list_devices(subsystem=subsystem): self.raise_event(('add', subsystem), device) self.raise_event(('add', subsystem, device.sys_name), device)
def start_inhibit(self): self.notification = self.notifier.get_dbus_method('Notify', \ 'org.freedesktop.Notifications') self.observer = MonitorObserver(self.monitor, callback = self.device_detected, name='monitor-usb-session') self.notifier.connect_to_signal('ActionInvoked', self.action_new_device) self.observer.daemon = True self.observer.start() print("Start monitoring Dbus session message") self.usb_blocker.get_dbus_method('start', 'org.gnome.USBBlocker.inhibit')()
def start_udev_tasks(self): """Start monitoring system devices using udev.""" def udev_handler(action, device): if device.subsystem in ('net', 'block'): self.raise_event((action, device.subsystem), device) self.raise_event((action, device.subsystem, device.sys_name), device) # Monitor interesting system events. self.monitor = Monitor.from_netlink(self.udev) self.observer = MonitorObserver(self.monitor, from_thread(udev_handler)) self.observer.start() # Trigger missed events. reactor.callLater(0, self.raise_missed_udev_events)
class USB_Session_Blocker(dbus.service.Object): # Create context context = Context() # Create monitor monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='usb', device_type='usb_device') def __init__(self): try: with open(expanduser("~") + '/.local/share/trusted_devices', 'rt') as f_in: try: self.trusted_devices = json.load(f_in) except ValueError: self.trusted_devices = [] except IOError: self.trusted_devices = [] self.usb_blocker = dbus.SystemBus().get_object( 'org.gnome.USBBlocker', '/org/gnome/USBBlocker') self.notifier = dbus.SessionBus().get_object( 'org.freedesktop.Notifications', '/org/freedesktop/Notifications') self.observer = None self.number_notifications = {} self.allowed_devices = [] bus_name = dbus.service.BusName('org.gnome.USBInhibit', bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, '/org/gnome/USBInhibit') @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='', out_signature='b') def get_status(self): return self.usb_blocker.get_dbus_method( 'get_status', 'org.gnome.USBBlocker.inhibit')() @dbus.service.method(dbus_interface='org.gnome.USBInhibit') def start_inhibit(self): self.notification = self.notifier.get_dbus_method('Notify', \ 'org.freedesktop.Notifications') self.observer = MonitorObserver(self.monitor, callback=self.device_detected, name='monitor-usb-session') self.notifier.connect_to_signal('ActionInvoked', self.action_new_device) self.observer.daemon = True self.observer.start() print("Start monitoring Dbus session message") self.usb_blocker.get_dbus_method('start', 'org.gnome.USBBlocker.inhibit')() def action_new_device(self, id, action): if id in self.number_notifications: if action == "Allow": print "Allowed" bus_id, dev_id = self.number_notifications.pop(id) if self.usb_blocker.get_dbus_method( 'enable_device', 'org.gnome.USBBlocker.device')(bus_id, dev_id): self.trusted_devices.append(dev_id) self.write_trusted_devices() print(bus_id) print(dev_id) # If the action is Block then the device must remain blocked if action == "Block": print "Blocked" @dbus.service.method(dbus_interface='org.gnome.USBInhibit') def stop_inhibit(self): print("Stop monitoring Dbus session message") if self.observer != None: self.observer.stop() self.usb_blocker.get_dbus_method('stop', 'org.gnome.USBBlocker.inhibit')() @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='n', out_signature='') def add_nonblock_device(self, bDeviceClass): print("Add device with the bDeviceClass code " + str(bDeviceClass)) self.allowed_devices.append(bDeviceClass) @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='n', out_signature='') def remove_nonblock_device(self, bDeviceClass): print("Remove device with the bDeviceClass code " + str(bDeviceClass)) if bDeviceClass in self.allowed_devices: self.allowed_devices.remove(bDeviceClass) @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='', out_signature='s') def show_nonblock_devices(self): return str(self.allowed_devices) def device_detected(self, device): import usb.core bus_id = device.sys_name action = device.action # Check only new connected devices to see if they are on an allowed list if action == 'add': print("Device attached") devnum = int(device.attributes.get("devnum")) busnum = int(device.attributes.get("busnum")) dev = usb.core.find(address=devnum, bus=busnum) # Get the device unique id dev_id = read_device.get_descriptors(dev) if dev_id in self.trusted_devices: self.usb_blocker.get_dbus_method( 'enable_device', 'org.gnome.USBBlocker.device')(bus_id, dev_id) return if read_device.find_device( dev, list( usb.core.find(find_all=True, custom_match=read_device.custom_search( self.allowed_devices)))): print("Device found on the non blocking list -- session") if self.usb_blocker.get_dbus_method( 'enable_device', 'org.gnome.USBBlocker.device')(bus_id, dev_id): self.trusted_devices.append(dev_id) self.write_trusted_devices() return id_notification = self.notification( "USB-inhibitor", "0", "", "Unknown device connected", "An unknown device has been connected to the system. Do you want to allow it to connect?", ["Allow", "Connect", "Block", "Block"], {}, 5) self.number_notifications[id_notification] = [bus_id, dev_id] def write_trusted_devices(self): with open(expanduser("~") + '/.local/share/trusted_devices', 'wt') as f_out: json.dump(self.trusted_devices, f_out)
def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, test_dir=None): # Check if process exists exit_code = subprocess.call(['pgrep', 'razer-service'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) if exit_code == 0: print("Daemon already exists. Please stop that one.", file=sys.stderr) exit(-1) setproctitle.setproctitle('razer-service') # Expanding ~ as python doesnt do it by default, also creating dirs if needed if log_dir is not None: log_dir = os.path.expanduser(log_dir) os.makedirs(log_dir, mode=0o750, exist_ok=True) if run_dir is not None: run_dir = os.path.expanduser(run_dir) os.makedirs(run_dir, mode=0o750, exist_ok=True) if config_file is not None: config_file = os.path.expanduser(config_file) os.makedirs(os.path.dirname(config_file), mode=0o750, exist_ok=True) self._test_dir = test_dir self._data_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) DBusService.__init__(self, self.BUS_PATH, '/org/razer') self._init_signals() self._main_loop = GObject.MainLoop() # Listen for input events from udev self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='input') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') # Logging logging_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): logging_level = logging.DEBUG self.logger = logging.getLogger('razer') self.logger.setLevel(logging_level) formatter = logging.Formatter( '%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Dont propagate to default logger self.logger.propagate = 0 if console_log: console_logger = logging.StreamHandler() console_logger.setLevel(logging_level) console_logger.setFormatter(formatter) self.logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler( log_file, maxBytes=16777216, backupCount=10) # 16MiB file_logger.setLevel(logging_level) file_logger.setFormatter(formatter) self.logger.addHandler(file_logger) self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) # Setup screensaver thread self._screensaver_thread = ScreensaverThread( self, active=self._config.getboolean('Startup', 'devices_off_on_screensaver')) self._screensaver_thread.start() self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods self.logger.info("Adding razer.devices.getDevices method to DBus") self.add_dbus_method('razer.devices', 'getDevices', self.get_serial_list, out_signature='as') self.logger.info( "Adding razer.devices.enableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver) self.logger.info( "Adding razer.devices.disableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'disableTurnOffOnScreensaver', self.disable_turn_off_on_screensaver) self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'syncEffects', self.sync_effects, in_signature='b') self.logger.info("Adding razer.daemon.version method to DBus") self.add_dbus_method('razer.daemon', 'version', self.version, out_signature='s') self.logger.info("Adding razer.daemon.stop method to DBus") self.add_dbus_method('razer.daemon', 'stop', self.stop) # TODO remove self.sync_effects( self._config.getboolean('Startup', 'sync_effects_enabled'))
def _stop(self): MonitorObserver.send_stop(self)
class KeyboardControl: """The keyboard control for the player""" def __init__(self, player): try: self.player = player # Create a context, create monitor at kernel level, select devices context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='input') self.observer = MonitorObserver(monitor, self.usb_event_callback, name="keyboard") self.observer.start() self.pressed = False # Stores state of press # Check if there is already a keyboard attached for device in context.list_devices(subsystem='input'): if device.get('ID_INPUT_KEYBOARD') == '1': if device.get('DEVNAME') != None: device_name = InputDevice(device.get('DEVNAME')) thread = threading.Thread(target=self.keyboard_event, args=(device_name,), daemon=True) thread.start() continue except Exception as ex: print('Keyboard Control: Error starting: ' + str(ex)) def usb_event_callback(self, action, device): """Callback when a usb device is plugged in""" if action == 'add' and device.get('ID_INPUT_KEYBOARD') == '1': print('Keyboard: input add') if device.get('DEVNAME') != None: device_name = InputDevice(device.get('DEVNAME')) thread = threading.Thread(target=self.keyboard_event, args=(device_name,), daemon=True) thread.start() def key_input(self, key_pressed): print('Keyboard Control: Key pressed: ' + key_pressed) if key_pressed == 'KEY_SPACE': if self.player.is_playing: self.player.pause_command('') else: self.player.play_command('') elif key_pressed == 'KEY_L': self.player.loop_command('') elif key_pressed == 'KEY_Z': self.player.stop_command('') elif key_pressed == 'KEY_X': self.player.video_mute_command('1') elif key_pressed == 'KEY_C': self.player.video_mute_command('0') elif key_pressed == 'KEY_V': self.player.audio_mute_command('1') elif key_pressed == 'KEY_B': self.player.audio_mute_command('0') elif key_pressed == 'KEY_S': self.player.stop_command('') def keyboard_event(self, device): """Handles keyboard events""" try: for event in device.read_loop(): # This is a key press if event.type == ecodes.EV_KEY: # pylint: disable=no-member # It is a press down if event.value == 1: # This is the first press we've seen if self.pressed != True: self.pressed = True self.key_input(ecodes.KEY[event.code]) # pylint: disable=no-member # Key released elif event.value == 0: self.pressed = False except Exception as ex: print('Keyboard control: Event error (most likely unplugged)' + str(ex))
def __init__(self): self.device_monitor = USB_ports(RunningMode.GTK) self.observer = MonitorObserver(self.device_monitor.monitor, callback = self.refresh, name='monitor-observer') Gtk.Window.__init__(self, title = "USBGnomento") self.set_resizable(True) self.set_border_width(10) # Setting up the self.grid in which the elements are to be positionned self.grid = Gtk.Grid() self.grid.set_column_homogeneous(True) self.grid.set_row_homogeneous(True) self.add(self.grid) # Creating the ListStore model self.usb_list = Gtk.ListStore(str, bool, str, str, str) self.current_filter_usb = None # Creating the filter, feeding it with the usb_list model self.usb_filter = self.usb_list.filter_new() # Setting the filter function self.usb_filter.set_visible_func(self.usb_filter_func) self.treeview = Gtk.TreeView.new_with_model(self.usb_filter) col = Gtk.TreeViewColumn("Known Device", Gtk.CellRendererPixbuf(), stock_id = 0) self.treeview.append_column(col) for i, column_title in enumerate(["Connected", "DescriptorInfo", "Manufacturer", "Product"]): i = i + 1 renderer = Gtk.CellRendererText() renderer.set_property('cell-background', 'grey') column = Gtk.TreeViewColumn(column_title, renderer, text=i) self.treeview.append_column(column) # Creating buttons to filter by device state, and setting up their events self.buttons = list() for usb_type in ["Connected Devices", "Known Devices", "Unknown Devices"]: button = Gtk.Button(usb_type) self.buttons.append(button) button.connect("clicked", self.on_selection_button_clicked) self.scrollable_treelist = Gtk.ScrolledWindow() self.scrollable_treelist.set_vexpand(True) self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10) # Write to know devices button = Gtk.Button("Write selected") self.buttons.append(button) button.connect("clicked", self.write_to_known_devices) # Remove trusted device button = Gtk.Button("Remove selected") self.buttons.append(button) button.connect("clicked", self.remove_from_known_devices) self.grid.attach_next_to(self.buttons[0], self.scrollable_treelist, Gtk.PositionType.BOTTOM, 1, 1) for i, button in enumerate(self.buttons[1:]): self.grid.attach_next_to(button, self.buttons[i], Gtk.PositionType.RIGHT, 1, 1) self.scrollable_treelist.add(self.treeview) self.first_populate_table() self.show_all() self.observer.start()
class RazerDaemon(DBusService): """ Daemon class This class sets up the main run loop which serves DBus messages. The logger is initialised in this module as well as finding and initialising devices. Serves the following functions via DBus * getDevices - Returns a list of serial numbers * enableTurnOffOnScreensaver - Starts/Continues the run loop on the screensaver thread * disableTurnOffOnScreensaver - Pauses the run loop on the screensaver thread """ BUS_PATH = 'org.razer' def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, test_dir=None): # Check if process exists exit_code = subprocess.call(['pgrep', 'razer-service'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) if exit_code == 0: print("Daemon already exists. Please stop that one.", file=sys.stderr) exit(-1) setproctitle.setproctitle('razer-service') # Expanding ~ as python doesnt do it by default, also creating dirs if needed if log_dir is not None: log_dir = os.path.expanduser(log_dir) os.makedirs(log_dir, mode=0o750, exist_ok=True) if run_dir is not None: run_dir = os.path.expanduser(run_dir) os.makedirs(run_dir, mode=0o750, exist_ok=True) if config_file is not None: config_file = os.path.expanduser(config_file) os.makedirs(os.path.dirname(config_file), mode=0o750, exist_ok=True) self._test_dir = test_dir self._data_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) DBusService.__init__(self, self.BUS_PATH, '/org/razer') self._init_signals() self._main_loop = GObject.MainLoop() # Listen for input events from udev self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='input') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') # Logging logging_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): logging_level = logging.DEBUG self.logger = logging.getLogger('razer') self.logger.setLevel(logging_level) formatter = logging.Formatter('%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Dont propagate to default logger self.logger.propagate = 0 if console_log: console_logger = logging.StreamHandler() console_logger.setLevel(logging_level) console_logger.setFormatter(formatter) self.logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler(log_file, maxBytes=16777216, backupCount=10) # 16MiB file_logger.setLevel(logging_level) file_logger.setFormatter(formatter) self.logger.addHandler(file_logger) self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) # Setup screensaver thread self._screensaver_thread = ScreensaverThread(self, active=self._config.getboolean('Startup', 'devices_off_on_screensaver')) self._screensaver_thread.start() self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods self.logger.info("Adding razer.devices.getDevices method to DBus") self.add_dbus_method('razer.devices', 'getDevices', self.get_serial_list, out_signature='as') self.logger.info("Adding razer.devices.enableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver) self.logger.info("Adding razer.devices.disableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'disableTurnOffOnScreensaver', self.disable_turn_off_on_screensaver) self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'syncEffects', self.sync_effects, in_signature='b') self.logger.info("Adding razer.daemon.version method to DBus") self.add_dbus_method('razer.daemon', 'version', self.version, out_signature='s') self.logger.info("Adding razer.daemon.stop method to DBus") self.add_dbus_method('razer.daemon', 'stop', self.stop) # TODO remove self.sync_effects(self._config.getboolean('Startup', 'sync_effects_enabled')) # TODO ====== def _init_signals(self): """ Heinous hack to properly handle signals on the mainloop. Necessary if we want to use the mainloop run() functionality. """ def signal_action(signum): """ Action to take when a signal is trapped """ self.quit(signum) def idle_handler(): """ GLib idle handler to propagate signals """ GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH) def handler(*args): """ Unix signal handler """ signal_action(args[0]) def install_glib_handler(sig): """ Choose a compatible method and install the handler """ unix_signal_add = None if hasattr(GLib, "unix_signal_add"): unix_signal_add = GLib.unix_signal_add elif hasattr(GLib, "unix_signal_add_full"): unix_signal_add = GLib.unix_signal_add_full if unix_signal_add: unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig) else: print("Can't install GLib signal handler!") for sig in signal.SIGINT, signal.SIGTERM, signal.SIGHUP: signal.signal(sig, idle_handler) GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH) def read_config(self, config_file): """ Read in the config file and set the defaults :param config_file: Config file :type config_file: str or None """ # Generate sections as trying to access a value even if a default exists will die if the section does not for section in ('General', 'Startup', 'Statistics'): self._config[section] = {} self._config['DEFAULT'] = { 'verbose_logging': True, 'sync_effects_enabled': True, 'devices_off_on_screensaver': True, 'key_statistics': False, } if config_file is not None and os.path.exists(config_file): self._config.read(config_file) def enable_turn_off_on_screensaver(self): """ Enable the turning off of devices when the screensaver is active """ self._screensaver_thread.active = True def disable_turn_off_on_screensaver(self): """ Disable the turning off of devices when the screensaver is active """ self._screensaver_thread.active = False def version(self): """ Get the daemon version :return: Version string :rtype: str """ return __version__ def suspend_devices(self): """ Suspend all devices """ for device in self._razer_devices: device.dbus.suspend_device() def resume_devices(self): """ Resume all devices """ for device in self._razer_devices: device.dbus.resume_device() def get_serial_list(self): """ Get list of devices serials """ serial_list = self._razer_devices.serials() self.logger.debug('DBus called get_serial_list') return serial_list def sync_effects(self, enabled): """ Sync the effects across the devices :param enabled: True to sync effects :type enabled: bool """ # Todo perhaps move logic to device collection for device in self._razer_devices.devices: device.dbus.effect_sync = enabled def _load_devices(self, first_run=False): """ Go through supported devices and load them Loops through the available hardware classes, loops through each device in the system and adds it if needs be. """ classes = razer_daemon.hardware.get_device_classes() if first_run: # Just some pretty output max_name_len = max([len(cls.__name__) for cls in classes]) + 2 for cls in classes: format_str = 'Loaded device specification: {0:-<' + str(max_name_len) + '} ({1:04x}:{2:04X})' self.logger.debug(format_str.format(cls.__name__ + ' ', cls.USB_VID, cls.USB_PID)) for device in self._udev_context.list_devices(subsystem='hid'): device_number = 0 for device_class in classes: if device.sys_name in self._razer_devices: continue if device_class.match(device.sys_name, device.parent.sys_path): # Check it matches sys/ ID format and has device_type file self.logger.info('Found device.%d: %s', device_number, device.sys_name) razer_device = device_class(device.sys_path, device_number, self._config, testing=self._test_dir is not None) # Wireless devices sometimes dont listen count = 0 while count < 3: # Loop to get serial, exit early if it gets one device_serial = razer_device.get_serial() if len(device_serial) > 0: break count += 1 else: logging.warning("Could not get serial for device {0}. Skipping".format(device.sys_name)) continue self._razer_devices.add(device.sys_name, device_serial, razer_device) device_number += 1 def _remove_devices(self): """ Go through the list of current devices and if they no longer exist then remove them """ hid_devices = [dev.sys_name for dev in self._udev_context.list_devices(subsystem='hid')] devices_to_remove = [dev for dev in self._razer_devices if dev not in hid_devices] for device in devices_to_remove: if self._test_dir is not None: # Remove from DBus device.dbus.remove_from_connection() # Remove device self.logger.warning("Device %s is missing. Removing from DBus", device.device_id) del self._razer_devices[device.device_id] def _udev_input_event(self, device): self.logger.debug('Device event [%s]: %s', device.action, device.device_path) if device.action == 'add': self._load_devices() elif device.action == 'remove': self._remove_devices() def run(self): """ Run the daemon """ self.logger.info('Serving DBus') # Start listening for device changes self._udev_observer.start() # Start the mainloop try: self._main_loop.run() except KeyboardInterrupt: self.logger.debug('Shutting down') def stop(self): """ Wrapper for quit """ self.quit(None) def quit(self, signum): """ Quit by stopping the main loop, observer, and screensaver thread """ # pylint: disable=unused-argument if signum is None: self.logger.info('Stopping daemon.') else: self.logger.info('Stopping daemon on signal %d', signum) self._main_loop.quit() # Stop udev monitor self._udev_observer.send_stop() # Stop screensaver self._screensaver_thread.shutdown = True self._screensaver_thread.join(timeout=2) if self._screensaver_thread.is_alive(): self.logger.warning('Could not stop the screensaver thread') for device in self._razer_devices: device.dbus.close()
def get_observer(): ctx = Context() mon = Monitor.from_netlink(ctx) mon.filter_by('block') return MonitorObserver(mon, callback=callback)
class DiskManager(object): """ Disk manager utility class """ def __init__(self, peppy): """ Initializer. :param peppy: main player class """ self.peppy = peppy self.context = Context() config = peppy.util.config self.read_only = config[DISK_MOUNT][MOUNT_READ_ONLY] self.mount_point_base = config[DISK_MOUNT][MOUNT_POINT].strip() self.mount_options = config[DISK_MOUNT][MOUNT_OPTIONS].strip().replace(" ", "") if not self.mount_point_base.endswith(os.sep): self.mount_point_base += os.sep self.disk_index = 0 self.observer = None def get_mount_point(self, device_name): """ Get the device mount point (if any) :param device_name: the device name e.g. /dev/sda1 :return: the mount point or None """ try: command = f"findmnt -n -S {device_name} -o TARGET" return check_output(command.split()).decode(UTF8).rstrip("\n") except CalledProcessError as e: logging.debug(e) return None def get_usb_disks(self): """ Get the list of dictionaries representing each connected disk :return: list of connected disks with such properties as label, device name etc. """ disks = [] for device in self.context.list_devices(subsystem='block', DEVTYPE='partition'): if device.get('ID_BUS') and device.get('ID_BUS') == 'usb': props = self.get_device_properties(device) if props: disks.append(props) return disks def get_device_properties(self, device): """ Get only required properties from the device object :param device: the device object :return: the dictionary with required properties """ if not device: return None props = {} if device.get('ID_FS_LABEL_ENC'): props[PROPERTY_NAME] = self.clean_string(device.get('ID_FS_LABEL_ENC')) else: self.disk_index += 1 props[PROPERTY_NAME] = BASE_NAME + str(self.disk_index) props[PROPERTY_UUID] = self.clean_string(device.get('ID_FS_UUID_ENC')) props[PROPERTY_DEVICE_NAME] = device.get('DEVNAME') props[PROPERTY_VENDOR] = device.get('ID_VENDOR') props[PROPERTY_MODEL] = self.clean_string(device.get('ID_MODEL_ENC')) props[PROPERTY_FILESYSTEM_TYPE] = device.get('ID_FS_TYPE') mount_point = self.get_mount_point(props[PROPERTY_DEVICE_NAME]) if mount_point != None: props[PROPERTY_MOUNT_POINT] = self.get_mount_point(props[PROPERTY_DEVICE_NAME]) props[PROPERTY_MOUNTED] = True else: props[PROPERTY_MOUNT_POINT] = "" props[PROPERTY_MOUNTED] = False return props def clean_string(self, s): """ Clean input string - replace space code by space and trim :param s: the input string :return: the processed string """ return s.replace(SPACE_CODE, SPACE).strip() def mount(self, device_properties): """ Mount device :param device_properties: the dictionary of the properties of the device to mount :return: True - disk mount was successful, False - otherwise """ device_name = device_properties[PROPERTY_DEVICE_NAME] existing_mount_point = device_properties[PROPERTY_MOUNT_POINT] label = device_properties[PROPERTY_NAME] mounted = device_properties[PROPERTY_MOUNTED] if mounted: logging.debug(f"Device {device_name} mounted already to {existing_mount_point}") return True mount_point = self.mount_point_base + label if os.path.ismount(mount_point): logging.debug(f"The mount point {mount_point} is in use already") return False if os.path.exists(mount_point): logging.debug(f"The mount point {mount_point} exists") else: try: os.makedirs(mount_point) except Exception as e: logging.debug(e) return False if self.read_only: command = "sudo mount -o ro".split() else: command = "sudo mount".split() if self.mount_options: command.append("-o") command.append(self.mount_options) command.append(device_name); command.append(mount_point); p = Popen(command, stdout=PIPE, stderr=PIPE) _, error = p.communicate() if p.returncode != 0: logging.debug(f"Mount failed with error: {error.decode(UTF8).rstrip(EOL)}") logging.debug(f"Failed mount command: {command}") return False else: logging.debug(f"Successfully mounted {device_name} to {mount_point}") return True def unmount(self, device_properties): """ Unmount device :param device_properties: the dictionary of the properties of the device to unmount :return: True - disk unmount was successful, False - otherwise """ device_name = device_properties[PROPERTY_DEVICE_NAME] p = Popen(["sudo", "umount", device_name], stdout=PIPE, stderr=PIPE) _, error = p.communicate() if p.returncode != 0: logging.debug(f"Unmount failed with error: {error.decode(UTF8).rstrip(EOL)}") return False else: logging.debug(f"Successfully unmounted {device_name}") return True def poweroff(self, device_properties): """ Poweroff provided device. If device is busy switch off player, go to Home, umnount and poweroff :param device_properties: the dictionary of the properties of the device to poweroff :return: True - disk poweroff was successful, False - otherwise """ device_name = device_properties[PROPERTY_DEVICE_NAME] mounted = self.get_mount_point(device_name) if mounted: unmounted = self.unmount(device_properties) if not unmounted: self.peppy.player.stop() self.peppy.go_home(None) self.unmount(device_properties) try: p = Popen(["sudo", "udisksctl", "power-off", "-b", device_name], stdout=PIPE, stderr=PIPE) _, error = p.communicate() if p.returncode != 0: logging.debug(f"Poweroff failed with error: {error.decode(UTF8).rstrip(EOL)}") return False else: logging.debug(f"Poweroff successful for device {device_name}") return True except Exception as e: logging.debug(e) def mount_all_usb_disks(self): """ Mount all USB disks found in the system """ disks = self.get_usb_disks() for d in disks: self.mount(d) def unmount_all_usb_disks(self): """ Unmount all USB disks found in the system """ disks = self.get_usb_disks() for d in disks: self.unmount(d) def poweroff_all_usb_disks(self): """ Poweroff all USB disks found in the system """ disks = self.get_usb_disks() for d in disks: self.poweroff(d) def usb_event_handler(self, device): """ Handle USB plug/unplug events :param device: the plugged/unplugged USB device """ if device and device.get('ID_BUS') and device.get('ID_BUS') == 'usb': device_properties = self.get_device_properties(device) if device.action == "add": self.mount(device_properties) elif device.action == "remove": unmounted = self.unmount(device_properties) if not unmounted: self.peppy.player.stop() title_screen_name = self.peppy.get_title_screen_name() self.peppy.stop_player_timer_thread(title_screen_name) if self.peppy.is_player_screen(): self.peppy.go_home(None) self.peppy.web_server.redraw_web_ui() self.unmount(device_properties) def start_observer(self): """ Start plug/unplug event observer """ monitor = Monitor.from_netlink(self.context) monitor.filter_by(subsystem="block", device_type="partition") self.observer = MonitorObserver(monitor, callback=self.usb_event_handler) self.observer.start() logging.debug("Started USB drive plug/unplug observer")
break if not found: if d in __cached_devices: __cached_devices.remove(d) for l in device_removed_listeners: l(d) break try: from pyudev import Context, Monitor, MonitorObserver __context = Context() __monitor = Monitor.from_netlink(__context) def handle_device_event(device=None): if device.action == "add": __device_added(device) if action == "removed": __device_removed(device) __observer = MonitorObserver(__monitor, callback=handle_device_event, name='monitor-observer') find_all_devices() have_udev = True __monitor.start() except Exception as e: logger.info("Failed to get PyUDev context, hot plugging support not available", exc_info = e) if __name__ == "__main__": for device in find_all_devices(): print(str(device))
class GC_CModule_UdevMon(GC_CModule): MODULE_ID = 'udevmon' def __init__(self, gcclient): self.gcclient = gcclient logger.debug('Initialize Module: %s', self.MODULE_ID) # Running State self.Running = True # Setup pyudev contect and monitor: # 1 - Ensure the udev context and monitor is setup: self.setupUdevMonitor() # 2 - Get and send the current device list: gccommand = {} gccommand[GC_Utility.GC_MODULEID] = self.MODULE_ID response = self.getCurrentUSBDevices() logger.debug('Sending udev init data...') self.gcclient.sendResult(gccommand, response) # 3 - Start the Udev Monitor: self.startUdevMonitor(callback=self.udevMonitorHandler) def setupUdevMonitor(self, filter_subsystem='usb'): logger.debug('Setting up udev context...') self.udev_context = Context() logger.debug('Setting up monitor context...') self.udev_monitor = Monitor.from_netlink(self.udev_context) logger.debug('Setting up monitor filter...') self.udev_monitor.filter_by(subsystem=filter_subsystem) def startUdevMonitor(self, callback): observer_name = self.MODULE_ID + '-observer' logger.debug('Setting up udev monitor: %s' % observer_name) self.udev_observer = MonitorObserver(self.udev_monitor, callback=callback, name=observer_name) self.udev_observer.start() def udevMonitorHandler(self, device): """ Watch udev event and handle each of them. """ self.parseDeviceObj(device) def parseDeviceObj(self, device): #logger.debug('Udev Device :: PCI Slot Name: %s' % pprint.pformat(device.find_parent('pci')['PCI_SLOT_NAME'])) new_device_obj = {} # Get the device converted to a standard dict: (better for JSON sending) for item in device.items(): new_device_obj[item[0]] = item[1] # Get the tags, if they are there: tags_from_device = list(device.tags) if len(tags_from_device) > 0: new_device_obj['TAGS'] = tags_from_device else: new_device_obj['TAGS'] = [] #logger.debug('Udev Device Dict:\n%s' % pprint.pformat(new_device_obj)) return new_device_obj def getCurrentUSBDevices(self, filter_subsystem='usb'): logger.debug('Getting current USB Devices...') finalObj = {} parsed_devices = [] # Parse all USB Devices: for device in self.udev_context.list_devices( subsystem=filter_subsystem): new_device_obj = self.parseDeviceObj(device) parsed_devices.append(new_device_obj) # Prep for output: finalObj['current_devices'] = parsed_devices #logger.debug('Udev Devices Dict:\n%s' % pprint.pformat(finalObj)) return finalObj # jEnc = json.JSONEncoder(skipkeys=True) # json_blob = jEnc.encode(finalObj) # logger.debug('Udev Devices JSON:\n%s' % pprint.pformat(json_blob)) """ Function: handleTask Description: handle download commands """ def handleTask(self, gccommand): #self.gcclient.log(GC_Utility.DEBUG, 'downloadFile : Sending result...'); logger.debug('Sending result...') self.gcclient.sendResult(gccommand, response) def getModuleId(self): return self.MODULE_ID def quit(self): self.Running = False self.udev_observer.send_stop() return True
def run(self): observer = MonitorObserver(monitor, self.udev_action) observer.daemon = True observer.start()
def __registerUdevCallback(self): context = pyudev.Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='block') observer = MonitorObserver(monitor, callback=self.__checkUdevEvent, name='monitor-observer') observer.start()
class UDevBackend(BackendInterface): def __init__(self): self.context = Context() self.monitor = Monitor.from_netlink(self.context) self.monitor.filter_by('power_supply') self.percent_callback = None self.status_callback = None (self.battery, self.line_power) = self.find_devices() if not self.battery: raise BatteryNotFoundError() if not self.line_power: raise LinePowerNotFoundError() self.last_percent = -1 self.last_status = None def on_udev_event(device): if device == self.battery: self.battery = device percent = self.get_percent() if percent != self.last_percent: self.last_percent = percent if self.percent_callback: GLib.idle_add(self.percent_callback, percent) elif device == self.line_power: self.line_power = device status = self.get_status() if status != self.last_status: self.last_status = status if self.status_callback: GLib.idle_add(self.status_callback, status) # XXX I can't get udev (or acpi) to give me battery discharge events # without requiring system configuration so we have to poll interval = 20000 def poll_udev(): battery = Device.from_path(self.context, self.battery.device_path) on_udev_event(battery) GLib.timeout_add(interval, poll_udev) GLib.timeout_add(interval, poll_udev) self.observer = MonitorObserver(self.monitor, callback=on_udev_event) self.observer.start() def find_devices(self): line_power = None battery = None for device in self.context.list_devices(subsystem='power_supply'): device_type = device.attributes.asstring('type').lower() # TODO # 1. handle empty battery port # 2. handle multiple devices if device_type == 'battery': battery = device elif device_type == 'mains': line_power = device return (battery, line_power) def get_status(self) -> Status: is_online = int(self.line_power.attributes.get('online')) == 1 if is_online: return Status.CHARGING else: return Status.DISCHARGING def get_percent(self) -> float: return float(self.battery.attributes.get('capacity')) def on_status_change(self, fn: Callable[[Status], None]) -> None: self.status_callback = fn def on_percent_change(self, fn: Callable[[float], None]) -> None: self.percent_callback = fn
class USB_Session_Blocker(dbus.service.Object): # Create context context = Context() # Create monitor monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='usb', device_type='usb_device') def __init__(self): try: with open(expanduser("~") + '/.local/share/trusted_devices', 'rt') as f_in: try: self.trusted_devices = json.load(f_in) except ValueError: self.trusted_devices = [] except IOError: self.trusted_devices = [] self.usb_blocker = dbus.SystemBus().get_object('org.gnome.USBBlocker', '/org/gnome/USBBlocker') self.notifier = dbus.SessionBus().get_object('org.freedesktop.Notifications', '/org/freedesktop/Notifications') self.observer = None self.number_notifications = {} self.allowed_devices = [] bus_name = dbus.service.BusName('org.gnome.USBInhibit', bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, '/org/gnome/USBInhibit') @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='', out_signature='b') def get_status(self): return self.usb_blocker.get_dbus_method('get_status', 'org.gnome.USBBlocker.inhibit')() @dbus.service.method(dbus_interface='org.gnome.USBInhibit') def start_inhibit(self): self.notification = self.notifier.get_dbus_method('Notify', \ 'org.freedesktop.Notifications') self.observer = MonitorObserver(self.monitor, callback = self.device_detected, name='monitor-usb-session') self.notifier.connect_to_signal('ActionInvoked', self.action_new_device) self.observer.daemon = True self.observer.start() print("Start monitoring Dbus session message") self.usb_blocker.get_dbus_method('start', 'org.gnome.USBBlocker.inhibit')() def action_new_device(self, id, action): if id in self.number_notifications: if action == "Allow": print "Allowed" bus_id, dev_id = self.number_notifications.pop(id) if self.usb_blocker.get_dbus_method('enable_device', 'org.gnome.USBBlocker.device')(bus_id, dev_id): self.trusted_devices.append(dev_id) self.write_trusted_devices() print (bus_id) print (dev_id) # If the action is Block then the device must remain blocked if action == "Block": print "Blocked" @dbus.service.method(dbus_interface='org.gnome.USBInhibit') def stop_inhibit(self): print("Stop monitoring Dbus session message") if self.observer != None: self.observer.stop() self.usb_blocker.get_dbus_method('stop', 'org.gnome.USBBlocker.inhibit')() @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='n', out_signature='') def add_nonblock_device(self, bDeviceClass): print ("Add device with the bDeviceClass code " + str(bDeviceClass)) self.allowed_devices.append(bDeviceClass) @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='n', out_signature='') def remove_nonblock_device(self, bDeviceClass): print ("Remove device with the bDeviceClass code " + str(bDeviceClass)) if bDeviceClass in self.allowed_devices: self.allowed_devices.remove(bDeviceClass) @dbus.service.method(dbus_interface='org.gnome.USBInhibit', \ in_signature='', out_signature='s') def show_nonblock_devices(self): return str(self.allowed_devices) def device_detected(self, device): import usb.core bus_id = device.sys_name action = device.action # Check only new connected devices to see if they are on an allowed list if action == 'add': print ("Device attached") devnum = int(device.attributes.get("devnum")) busnum = int(device.attributes.get("busnum")) dev = usb.core.find(address=devnum, bus=busnum) # Get the device unique id dev_id = read_device.get_descriptors(dev) if dev_id in self.trusted_devices: self.usb_blocker.get_dbus_method('enable_device', 'org.gnome.USBBlocker.device')(bus_id, dev_id) return if read_device.find_device(dev, list(usb.core.find(find_all = True, custom_match = read_device.custom_search(self.allowed_devices)))): print ("Device found on the non blocking list -- session") if self.usb_blocker.get_dbus_method('enable_device', 'org.gnome.USBBlocker.device')(bus_id, dev_id): self.trusted_devices.append(dev_id) self.write_trusted_devices() return id_notification = self.notification("USB-inhibitor", "0", "", "Unknown device connected", "An unknown device has been connected to the system. Do you want to allow it to connect?", ["Allow", "Connect", "Block", "Block"], {}, 5) self.number_notifications[id_notification] = [bus_id, dev_id] def write_trusted_devices(self): with open(expanduser("~") + '/.local/share/trusted_devices', 'wt') as f_out: json.dump(self.trusted_devices, f_out)
from subprocess import call def transfer_video(observer, device): if device.action == 'add' and device.get('DEVTYPE') == 'usb_device': sleep(5) print("Type: {0}".format(device.get('DEVTYPE'))) print("NAME: {0}".format(device.get('DEVNAME'))) devName = device.get('DEVNAME').split("/") phonePath = "/run/user/1000/gvfs/mtp:host=%5Busb%3A" + devName[4] + "%2C" + devName[5] + "%5D/Phone" print(phonePath) if path.exists(phonePath): if not path.exists(phonePath + "/motomatedata"): makedirs(phonePath + "/motomatedata") for file in listdir("/home/pi/Design/piCam/Video"): system("sudo cp /home/pi/Design/piCam/Video/" + file + " " + phonePath + "/motomatedata") #: #call(["rm", "/home/pi/Design/piCam/Video/" + file]) #print("Whoopsie") context = Context() monitor = Monitor.from_netlink(context) #monitor.filter_by(subsystem='bus') observer = MonitorObserver(monitor, transfer_video) monitor.start() observer.start()
if device.device_type == 'disk' and device.get('ID_VENDOR_ID') == '1fc9': if action == 'add': print('get a device') subprocess.call([DOWNLOAD_TOOL, DOWNLOAD_FILE]) GPIO.output(BLUE_LED, GPIO.HIGH) elif action == 'remove': print('device is removed') GPIO.output(BLUE_LED, GPIO.LOW) print('Auto download deamon') context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='block') observer = MonitorObserver(monitor, device_event) print('Start to detect usb mass storage') observer.start() try: while True: GPIO.output(GREEN_LED, GPIO.HIGH) sleep(1) GPIO.output(GREEN_LED, GPIO.LOW) sleep(1) except Exception as e: print(e) print('exit') GPIO.cleanup()
def _init_udev_monitor(self): self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='hid') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor')
class RazerDaemon(DBusService): """ Daemon class This class sets up the main run loop which serves DBus messages. The logger is initialised in this module as well as finding and initialising devices. Serves the following functions via DBus * getDevices - Returns a list of serial numbers * enableTurnOffOnScreensaver - Starts/Continues the run loop on the screensaver thread * disableTurnOffOnScreensaver - Pauses the run loop on the screensaver thread """ BUS_PATH = 'org.razer' def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, test_dir=None): # Check if process exists exit_code = subprocess.call(['pgrep', 'razer-daemon'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) if exit_code == 0: print("Daemon already exists. Please stop that one.", file=sys.stderr) exit(-1) setproctitle.setproctitle('razer-daemon') # Expanding ~ as python doesnt do it by default, also creating dirs if needed if log_dir is not None: log_dir = os.path.expanduser(log_dir) os.makedirs(log_dir, mode=0o750, exist_ok=True) if run_dir is not None: run_dir = os.path.expanduser(run_dir) os.makedirs(run_dir, mode=0o750, exist_ok=True) if config_file is not None: config_file = os.path.expanduser(config_file) os.makedirs(os.path.dirname(config_file), mode=0o750, exist_ok=True) self._test_dir = test_dir self._data_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) DBusService.__init__(self, self.BUS_PATH, '/org/razer') self._init_signals() self._main_loop = GObject.MainLoop() # Listen for input events from udev self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='hid') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') # Logging logging_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): logging_level = logging.DEBUG self.logger = logging.getLogger('razer') self.logger.setLevel(logging_level) formatter = logging.Formatter( '%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Dont propagate to default logger self.logger.propagate = 0 if console_log: console_logger = logging.StreamHandler() console_logger.setLevel(logging_level) console_logger.setFormatter(formatter) self.logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler( log_file, maxBytes=16777216, backupCount=10) # 16MiB file_logger.setLevel(logging_level) file_logger.setFormatter(formatter) self.logger.addHandler(file_logger) # Load Classes self._device_classes = razer_daemon.hardware.get_device_classes() self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) # Check for plugdev group try: plugdev_group = grp.getgrnam('plugdev') if getpass.getuser() not in plugdev_group.gr_mem: self.logger.critical( "User is not a member of the plugdev group") sys.exit(1) except KeyError: self.logger.warning( "Could not check if user is a member of the plugdev group. Continuing..." ) self._screensaver_monitor = ScreensaverMonitor(self) self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods self.logger.info("Adding razer.devices.getDevices method to DBus") self.add_dbus_method('razer.devices', 'getDevices', self.get_serial_list, out_signature='as') self.logger.info( "Adding razer.devices.enableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver, in_signature='b') self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'getOffOnScreensaver', self.get_off_on_screensaver, out_signature='b') self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'syncEffects', self.sync_effects, in_signature='b') self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'getSyncEffects', self.get_sync_effects, out_signature='b') self.logger.info("Adding razer.daemon.version method to DBus") self.add_dbus_method('razer.daemon', 'version', self.version, out_signature='s') self.logger.info("Adding razer.daemon.stop method to DBus") self.add_dbus_method('razer.daemon', 'stop', self.stop) # TODO remove self.sync_effects( self._config.getboolean('Startup', 'sync_effects_enabled')) # TODO ====== @dbus.service.signal('razer.devices') def device_removed(self): self.logger.debug("Emitted Device Remove Signal") @dbus.service.signal('razer.devices') def device_added(self): self.logger.debug("Emitted Device Added Signal") def _init_signals(self): """ Heinous hack to properly handle signals on the mainloop. Necessary if we want to use the mainloop run() functionality. """ def signal_action(signum): """ Action to take when a signal is trapped """ self.quit(signum) def idle_handler(): """ GLib idle handler to propagate signals """ GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH) def handler(*args): """ Unix signal handler """ signal_action(args[0]) def install_glib_handler(sig): """ Choose a compatible method and install the handler """ unix_signal_add = None if hasattr(GLib, "unix_signal_add"): unix_signal_add = GLib.unix_signal_add elif hasattr(GLib, "unix_signal_add_full"): unix_signal_add = GLib.unix_signal_add_full if unix_signal_add: unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig) else: print("Can't install GLib signal handler!") for sig in signal.SIGINT, signal.SIGTERM, signal.SIGHUP: signal.signal(sig, idle_handler) GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH) def read_config(self, config_file): """ Read in the config file and set the defaults :param config_file: Config file :type config_file: str or None """ # Generate sections as trying to access a value even if a default exists will die if the section does not for section in ('General', 'Startup', 'Statistics'): self._config[section] = {} self._config['DEFAULT'] = { 'verbose_logging': True, 'sync_effects_enabled': True, 'devices_off_on_screensaver': True, 'key_statistics': False, } if config_file is not None and os.path.exists(config_file): self._config.read(config_file) def get_off_on_screensaver(self): """ Returns if turn off on screensaver :return: Result :rtype: bool """ return self._screensaver_monitor.monitoring def enable_turn_off_on_screensaver(self, enable): """ Enable the turning off of devices when the screensaver is active """ self._screensaver_monitor.monitoring = enable def version(self): """ Get the daemon version :return: Version string :rtype: str """ return __version__ def suspend_devices(self): """ Suspend all devices """ for device in self._razer_devices: device.dbus.suspend_device() def resume_devices(self): """ Resume all devices """ for device in self._razer_devices: device.dbus.resume_device() def get_serial_list(self): """ Get list of devices serials """ serial_list = self._razer_devices.serials() self.logger.debug('DBus called get_serial_list') return serial_list def sync_effects(self, enabled): """ Sync the effects across the devices :param enabled: True to sync effects :type enabled: bool """ # Todo perhaps move logic to device collection for device in self._razer_devices.devices: device.dbus.effect_sync = enabled def get_sync_effects(self): """ Sync the effects across the devices :return: True if any devices sync effects :rtype: bool """ result = False for device in self._razer_devices.devices: result |= device.dbus.effect_sync return result def _load_devices(self, first_run=False): """ Go through supported devices and load them Loops through the available hardware classes, loops through each device in the system and adds it if needs be. """ if first_run: # Just some pretty output max_name_len = max( [len(cls.__name__) for cls in self._device_classes]) + 2 for cls in self._device_classes: format_str = 'Loaded device specification: {0:-<' + str( max_name_len) + '} ({1:04x}:{2:04X})' self.logger.debug( format_str.format(cls.__name__ + ' ', cls.USB_VID, cls.USB_PID)) if self._test_dir is not None: device_list = os.listdir(self._test_dir) test_mode = True else: device_list = list( self._udev_context.list_devices(subsystem='hid')) test_mode = False device_number = 0 for device in device_list: for device_class in self._device_classes: # Interoperability between generic list of 0000:0000:0000.0000 and pyudev if test_mode: sys_name = device sys_path = os.path.join(self._test_dir, device) else: sys_name = device.sys_name sys_path = device.sys_path if sys_name in self._razer_devices: continue if device_class.match( sys_name, sys_path ): # Check it matches sys/ ID format and has device_type file self.logger.info('Found device.%d: %s', device_number, sys_name) # TODO add testdir support # Basically find the other usb interfaces device_match = sys_name.split('.')[0] additional_interfaces = [] if not test_mode: for alt_device in device_list: if device_match in alt_device.sys_name and alt_device.sys_name != sys_name: additional_interfaces.append( alt_device.sys_path) # Checking permissions test_file = os.path.join(sys_path, 'device_type') file_group_id = os.stat(test_file).st_gid file_group_name = grp.getgrgid(file_group_id)[0] if os.getgid( ) != file_group_id and file_group_name != 'plugdev': self.logger.critical( "Could not access {0}/device_type, file is not owned by plugdev" .format(sys_path)) break razer_device = device_class( sys_path, device_number, self._config, testing=self._test_dir is not None, additional_interfaces=sorted(additional_interfaces)) # Wireless devices sometimes dont listen count = 0 while count < 3: # Loop to get serial, exit early if it gets one device_serial = razer_device.get_serial() if len(device_serial) > 0: break time.sleep(0.1) count += 1 else: logging.warning( "Could not get serial for device {0}. Skipping". format(sys_name)) continue self._razer_devices.add(sys_name, device_serial, razer_device) device_number += 1 def _add_device(self, device): """ Add device event from udev :param device: Udev Device :type device: pyudev.device._device.Device """ device_number = len(self._razer_devices) for device_class in self._device_classes: sys_name = device.sys_name sys_path = device.sys_path if sys_name in self._razer_devices: continue if device_class.match( sys_name, sys_path ): # Check it matches sys/ ID format and has device_type file self.logger.info('Found valid device.%d: %s', device_number, sys_name) razer_device = device_class(sys_path, device_number, self._config, testing=self._test_dir is not None) # Its a udev event so currently the device hasn't been chmodded yet time.sleep(0.2) # Wireless devices sometimes dont listen device_serial = razer_device.get_serial() if len(device_serial) > 0: # Add Device self._razer_devices.add(sys_name, device_serial, razer_device) self.device_added() else: logging.warning( "Could not get serial for device {0}. Skipping".format( sys_name)) def _remove_device(self, device): """ Remove device event from udev :param device: Udev Device :type device: pyudev.device._device.Device """ device_id = device.sys_name try: device = self._razer_devices[device_id] device.dbus.close() device.dbus.remove_from_connection() self.logger.warning("Removing %s", device_id) # Delete device del self._razer_devices[device.device_id] self.device_removed() except IndexError: # Why didnt i set it up as KeyError # It will return "extra" events for the additional usb interfaces bound to the driver pass def _udev_input_event(self, device): """ Function called by the Udev monitor (#observerPattern) :param device: Udev device :type device: pyudev.device._device.Device """ self.logger.debug('Device event [%s]: %s', device.action, device.device_path) if device.action == 'add': self._add_device(device) elif device.action == 'remove': self._remove_device(device) def run(self): """ Run the daemon """ self.logger.info('Serving DBus') # Start listening for device changes self._udev_observer.start() # Start the mainloop try: self._main_loop.run() except KeyboardInterrupt: self.logger.debug('Shutting down') def stop(self): """ Wrapper for quit """ self.quit(None) def quit(self, signum): """ Quit by stopping the main loop, observer, and screensaver thread """ # pylint: disable=unused-argument if signum is None: self.logger.info('Stopping daemon.') else: self.logger.info('Stopping daemon on signal %d', signum) self._main_loop.quit() # Stop udev monitor self._udev_observer.send_stop() for device in self._razer_devices: device.dbus.close()
class RazerDaemon(DBusService): """ Daemon class This class sets up the main run loop which serves DBus messages. The logger is initialised in this module as well as finding and initialising devices. Serves the following functions via DBus * getDevices - Returns a list of serial numbers * enableTurnOffOnScreensaver - Starts/Continues the run loop on the screensaver thread * disableTurnOffOnScreensaver - Pauses the run loop on the screensaver thread """ BUS_NAME = 'org.razer' def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, test_dir=None): setproctitle.setproctitle('openrazer-daemon') # pylint: disable=no-member # Expanding ~ as python doesn't do it by default, also creating dirs if needed try: if log_dir is not None: log_dir = os.path.expanduser(log_dir) os.makedirs(log_dir, exist_ok=True) if run_dir is not None: run_dir = os.path.expanduser(run_dir) os.makedirs(run_dir, exist_ok=True) except NotADirectoryError as e: print("Failed to create {}".format(e.filename), file=sys.stderr) sys.exit(1) if config_file is not None: config_file = os.path.expanduser(config_file) if not os.path.exists(config_file): print("Config file {} does not exist.".format(config_file), file=sys.stderr) sys.exit(1) self._test_dir = test_dir self._run_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Logging log_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): log_level = logging.DEBUG self.logger = self._create_logger(log_dir, log_level, console_log) # Check for plugdev group if not self._check_plugdev_group(): self.logger.critical("User is not a member of the plugdev group") sys.exit(1) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) DBusService.__init__(self, self.BUS_NAME, '/org/razer') self._init_signals() self._main_loop = GLib.MainLoop() # Listen for input events from udev self._init_udev_monitor() # Load Classes self._device_classes = openrazer_daemon.hardware.get_device_classes() self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) self._init_screensaver_monitor() self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods methods = { # interface, method, callback, in-args, out-args ('razer.devices', 'getDevices', self.get_serial_list, None, 'as'), ('razer.devices', 'supportedDevices', self.supported_devices, None, 's'), ('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver, 'b', None), ('razer.devices', 'getOffOnScreensaver', self.get_off_on_screensaver, None, 'b'), ('razer.devices', 'syncEffects', self.sync_effects, 'b', None), ('razer.devices', 'getSyncEffects', self.get_sync_effects, None, 'b'), ('razer.daemon', 'version', self.version, None, 's'), ('razer.daemon', 'stop', self.stop, None, None), } for m in methods: self.logger.debug("Adding {}.{} method to DBus".format(m[0], m[1])) self.add_dbus_method(m[0], m[1], m[2], in_signature=m[3], out_signature=m[4]) self._collecting_udev = False self._collecting_udev_devices = [] # TODO remove self.sync_effects(self._config.getboolean('Startup', 'sync_effects_enabled')) # TODO ====== @dbus.service.signal('razer.devices') def device_removed(self): self.logger.debug("Emitted Device Remove Signal") @dbus.service.signal('razer.devices') def device_added(self): self.logger.debug("Emitted Device Added Signal") def _create_logger(self, log_dir, log_level, want_console_log): """ Initializes a logger and returns it. :param log_dir: If not None, specifies the directory to create the log file in :param log_level: The log level of messages to print :param want_console_log: True if we should print to the console :rtype:logging.Logger """ logger = logging.getLogger('razer') logger.setLevel(log_level) formatter = logging.Formatter('%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Don't propagate to default logger logger.propagate = 0 if want_console_log: console_logger = logging.StreamHandler() console_logger.setLevel(log_level) console_logger.setFormatter(formatter) logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler(log_file, maxBytes=16777216, backupCount=10) # 16MiB file_logger.setLevel(log_level) file_logger.setFormatter(formatter) logger.addHandler(file_logger) return logger def _check_plugdev_group(self): """ Check if the user is a member of the plugdev group. For the root user, this always returns True :rtype: bool """ if getpass.getuser() == 'root': return True try: return grp.getgrnam('plugdev').gr_gid in os.getgroups() except KeyError: pass return False def _init_udev_monitor(self): self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='hid') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') def _init_screensaver_monitor(self): try: self._screensaver_monitor = ScreensaverMonitor(self) self._screensaver_monitor.monitoring = self._config.getboolean('Startup', 'devices_off_on_screensaver') except dbus.exceptions.DBusException as e: self.logger.error("Failed to init ScreensaverMonitor: {}".format(e)) def _init_signals(self): """ Heinous hack to properly handle signals on the mainloop. Necessary if we want to use the mainloop run() functionality. """ def signal_action(signum): """ Action to take when a signal is trapped """ self.quit(signum) def idle_handler(): """ GLib idle handler to propagate signals """ GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH) def handler(*args): """ Unix signal handler """ signal_action(args[0]) def install_glib_handler(sig): """ Choose a compatible method and install the handler """ unix_signal_add = None if hasattr(GLib, "unix_signal_add"): unix_signal_add = GLib.unix_signal_add elif hasattr(GLib, "unix_signal_add_full"): unix_signal_add = GLib.unix_signal_add_full if unix_signal_add: unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig) else: print("Can't install GLib signal handler!") for sig in signal.SIGINT, signal.SIGTERM, signal.SIGHUP: signal.signal(sig, idle_handler) GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH) def read_config(self, config_file): """ Read in the config file and set the defaults :param config_file: Config file :type config_file: str or None """ # Generate sections as trying to access a value even if a default exists will die if the section does not for section in ('General', 'Startup', 'Statistics'): self._config[section] = {} self._config['DEFAULT'] = { 'verbose_logging': True, 'sync_effects_enabled': True, 'devices_off_on_screensaver': True, 'key_statistics': False, } if config_file is not None and os.path.exists(config_file): self._config.read(config_file) def get_off_on_screensaver(self): """ Returns if turn off on screensaver :return: Result :rtype: bool """ return self._screensaver_monitor.monitoring def enable_turn_off_on_screensaver(self, enable): """ Enable the turning off of devices when the screensaver is active """ self._screensaver_monitor.monitoring = enable def supported_devices(self): result = {cls.__name__: (cls.USB_VID, cls.USB_PID) for cls in self._device_classes} return json.dumps(result) def version(self): """ Get the daemon version :return: Version string :rtype: str """ return __version__ def suspend_devices(self): """ Suspend all devices """ for device in self._razer_devices: device.dbus.suspend_device() def resume_devices(self): """ Resume all devices """ for device in self._razer_devices: device.dbus.resume_device() def get_serial_list(self): """ Get list of devices serials """ serial_list = self._razer_devices.serials() self.logger.debug('DBus called get_serial_list') return serial_list def sync_effects(self, enabled): """ Sync the effects across the devices :param enabled: True to sync effects :type enabled: bool """ # Todo perhaps move logic to device collection for device in self._razer_devices.devices: device.dbus.effect_sync = enabled def get_sync_effects(self): """ Sync the effects across the devices :return: True if any devices sync effects :rtype: bool """ result = False for device in self._razer_devices.devices: result |= device.dbus.effect_sync return result def _load_devices(self, first_run=False): """ Go through supported devices and load them Loops through the available hardware classes, loops through each device in the system and adds it if needs be. """ if first_run: # Just some pretty output max_name_len = max([len(cls.__name__) for cls in self._device_classes]) + 2 for cls in self._device_classes: format_str = 'Loaded device specification: {0:-<' + str(max_name_len) + '} ({1:04x}:{2:04X})' self.logger.debug(format_str.format(cls.__name__ + ' ', cls.USB_VID, cls.USB_PID)) if self._test_dir is not None: device_list = os.listdir(self._test_dir) test_mode = True else: device_list = list(self._udev_context.list_devices(subsystem='hid')) test_mode = False device_number = 0 for device in device_list: for device_class in self._device_classes: # Interoperability between generic list of 0000:0000:0000.0000 and pyudev if test_mode: sys_name = device sys_path = os.path.join(self._test_dir, device) else: sys_name = device.sys_name sys_path = device.sys_path if sys_name in self._razer_devices: continue if device_class.match(sys_name, sys_path): # Check it matches sys/ ID format and has device_type file self.logger.info('Found device.%d: %s', device_number, sys_name) # TODO add testdir support # Basically find the other usb interfaces device_match = sys_name.split('.')[0] additional_interfaces = [] if not test_mode: for alt_device in device_list: if device_match in alt_device.sys_name and alt_device.sys_name != sys_name: additional_interfaces.append(alt_device.sys_path) # Checking permissions test_file = os.path.join(sys_path, 'device_type') file_group_id = os.stat(test_file).st_gid file_group_name = grp.getgrgid(file_group_id)[0] if os.getgid() != file_group_id and file_group_name != 'plugdev': self.logger.critical("Could not access {0}/device_type, file is not owned by plugdev".format(sys_path)) break razer_device = device_class(sys_path, device_number, self._config, testing=self._test_dir is not None, additional_interfaces=sorted(additional_interfaces)) # Wireless devices sometimes don't listen count = 0 while count < 3: # Loop to get serial, exit early if it gets one device_serial = razer_device.get_serial() if len(device_serial) > 0: break time.sleep(0.1) count += 1 else: logging.warning("Could not get serial for device {0}. Skipping".format(sys_name)) continue self._razer_devices.add(sys_name, device_serial, razer_device) device_number += 1 def _add_device(self, device): """ Add device event from udev :param device: Udev Device :type device: pyudev.device._device.Device """ device_number = len(self._razer_devices) for device_class in self._device_classes: sys_name = device.sys_name sys_path = device.sys_path if sys_name in self._razer_devices: continue if device_class.match(sys_name, sys_path): # Check it matches sys/ ID format and has device_type file self.logger.info('Found valid device.%d: %s', device_number, sys_name) razer_device = device_class(sys_path, device_number, self._config, testing=self._test_dir is not None) # Its a udev event so currently the device hasn't been chmodded yet time.sleep(0.2) # Wireless devices sometimes don't listen device_serial = razer_device.get_serial() if len(device_serial) > 0: # Add Device self._razer_devices.add(sys_name, device_serial, razer_device) self.device_added() else: logging.warning("Could not get serial for device {0}. Skipping".format(sys_name)) else: # Basically find the other usb interfaces device_match = sys_name.split('.')[0] for d in self._razer_devices: if device_match in d.device_id and d.device_id != sys_name: if not sys_path in d.dbus.additional_interfaces: d.dbus.additional_interfaces.append(sys_path) return def _remove_device(self, device): """ Remove device event from udev :param device: Udev Device :type device: pyudev.device._device.Device """ device_id = device.sys_name try: device = self._razer_devices[device_id] device.dbus.close() device.dbus.remove_from_connection() self.logger.warning("Removing %s", device_id) # Delete device del self._razer_devices[device.device_id] self.device_removed() except IndexError: # Why didn't i set it up as KeyError # It will return "extra" events for the additional usb interfaces bound to the driver pass def _udev_input_event(self, device): """ Function called by the Udev monitor (#observerPattern) :param device: Udev device :type device: pyudev.device._device.Device """ self.logger.debug('Device event [%s]: %s', device.action, device.device_path) if device.action == 'add': if self._collecting_udev: self._collecting_udev_devices.append(device) return else: self._collecting_udev_devices = [device] self._collecting_udev = True t = threading.Thread(target=self._collecting_udev_method, args=(device,)) t.start() elif device.action == 'remove': self._remove_device(device) def _collecting_udev_method(self, device): time.sleep(2) # delay to let udev add all devices that we want # Sort the devices self._collecting_udev_devices.sort(key=lambda x: x.sys_path, reverse=True) for d in self._collecting_udev_devices: self._add_device(d) self._collecting_udev = False def run(self): """ Run the daemon """ self.logger.info('Serving DBus') # Start listening for device changes self._udev_observer.start() # Start the mainloop try: self._main_loop.run() except KeyboardInterrupt: self.logger.debug('Shutting down') def stop(self): """ Wrapper for quit """ self.quit(None) def quit(self, signum): """ Quit by stopping the main loop, observer, and screensaver thread """ # pylint: disable=unused-argument if signum is None: self.logger.info('Stopping daemon.') else: self.logger.info('Stopping daemon on signal %d', signum) self._main_loop.quit() # Stop udev monitor self._udev_observer.send_stop() for device in self._razer_devices: device.dbus.close()
def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, test_dir=None): # Check if process exists exit_code = subprocess.call(['pgrep', 'razer-service'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) if exit_code == 0: print("Daemon already exists. Please stop that one.", file=sys.stderr) exit(-1) setproctitle.setproctitle('razer-service') # Expanding ~ as python doesnt do it by default, also creating dirs if needed if log_dir is not None: log_dir = os.path.expanduser(log_dir) os.makedirs(log_dir, mode=0o750, exist_ok=True) if run_dir is not None: run_dir = os.path.expanduser(run_dir) os.makedirs(run_dir, mode=0o750, exist_ok=True) if config_file is not None: config_file = os.path.expanduser(config_file) os.makedirs(os.path.dirname(config_file), mode=0o750, exist_ok=True) self._test_dir = test_dir self._data_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) DBusService.__init__(self, self.BUS_PATH, '/org/razer') self._init_signals() self._main_loop = GObject.MainLoop() # Listen for input events from udev self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='input') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') # Logging logging_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): logging_level = logging.DEBUG self.logger = logging.getLogger('razer') self.logger.setLevel(logging_level) formatter = logging.Formatter('%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Dont propagate to default logger self.logger.propagate = 0 if console_log: console_logger = logging.StreamHandler() console_logger.setLevel(logging_level) console_logger.setFormatter(formatter) self.logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler(log_file, maxBytes=16777216, backupCount=10) # 16MiB file_logger.setLevel(logging_level) file_logger.setFormatter(formatter) self.logger.addHandler(file_logger) self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) # Setup screensaver thread self._screensaver_thread = ScreensaverThread(self, active=self._config.getboolean('Startup', 'devices_off_on_screensaver')) self._screensaver_thread.start() self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods self.logger.info("Adding razer.devices.getDevices method to DBus") self.add_dbus_method('razer.devices', 'getDevices', self.get_serial_list, out_signature='as') self.logger.info("Adding razer.devices.enableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver) self.logger.info("Adding razer.devices.disableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'disableTurnOffOnScreensaver', self.disable_turn_off_on_screensaver) self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'syncEffects', self.sync_effects, in_signature='b') self.logger.info("Adding razer.daemon.version method to DBus") self.add_dbus_method('razer.daemon', 'version', self.version, out_signature='s') self.logger.info("Adding razer.daemon.stop method to DBus") self.add_dbus_method('razer.daemon', 'stop', self.stop) # TODO remove self.sync_effects(self._config.getboolean('Startup', 'sync_effects_enabled'))
class USB_ViewFilterWindow(Gtk.Window): def __init__(self): self.device_monitor = USB_ports(RunningMode.GTK) self.observer = MonitorObserver(self.device_monitor.monitor, callback = self.refresh, name='monitor-observer') Gtk.Window.__init__(self, title = "USBGnomento") self.set_resizable(True) self.set_border_width(10) # Setting up the self.grid in which the elements are to be positionned self.grid = Gtk.Grid() self.grid.set_column_homogeneous(True) self.grid.set_row_homogeneous(True) self.add(self.grid) # Creating the ListStore model self.usb_list = Gtk.ListStore(str, bool, str, str, str) self.current_filter_usb = None # Creating the filter, feeding it with the usb_list model self.usb_filter = self.usb_list.filter_new() # Setting the filter function self.usb_filter.set_visible_func(self.usb_filter_func) self.treeview = Gtk.TreeView.new_with_model(self.usb_filter) col = Gtk.TreeViewColumn("Known Device", Gtk.CellRendererPixbuf(), stock_id = 0) self.treeview.append_column(col) for i, column_title in enumerate(["Connected", "DescriptorInfo", "Manufacturer", "Product"]): i = i + 1 renderer = Gtk.CellRendererText() renderer.set_property('cell-background', 'grey') column = Gtk.TreeViewColumn(column_title, renderer, text=i) self.treeview.append_column(column) # Creating buttons to filter by device state, and setting up their events self.buttons = list() for usb_type in ["Connected Devices", "Known Devices", "Unknown Devices"]: button = Gtk.Button(usb_type) self.buttons.append(button) button.connect("clicked", self.on_selection_button_clicked) self.scrollable_treelist = Gtk.ScrolledWindow() self.scrollable_treelist.set_vexpand(True) self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10) # Write to know devices button = Gtk.Button("Write selected") self.buttons.append(button) button.connect("clicked", self.write_to_known_devices) # Remove trusted device button = Gtk.Button("Remove selected") self.buttons.append(button) button.connect("clicked", self.remove_from_known_devices) self.grid.attach_next_to(self.buttons[0], self.scrollable_treelist, Gtk.PositionType.BOTTOM, 1, 1) for i, button in enumerate(self.buttons[1:]): self.grid.attach_next_to(button, self.buttons[i], Gtk.PositionType.RIGHT, 1, 1) self.scrollable_treelist.add(self.treeview) self.first_populate_table() self.show_all() self.observer.start() def first_populate_table(self): for device_id in self.device_monitor.known_devices.keys(): if device_id in self.device_monitor.connected_devices.keys(): self.usb_list.append([Gtk.STOCK_YES, True, self.device_monitor.known_devices[device_id][1], self.device_monitor.known_devices[device_id][0]["Manufacturer"], self.device_monitor.known_devices[device_id][0]["Product"]]) else: self.usb_list.append([Gtk.STOCK_YES, False, self.device_monitor.known_devices[device_id][1], self.device_monitor.known_devices[device_id][0]["Manufacturer"], self.device_monitor.known_devices[device_id][0]["Product"]]) for device_id in self.device_monitor.connected_devices.keys(): if device_id not in self.device_monitor.known_devices.keys(): print (self.device_monitor.connected_devices[device_id][1]) self.usb_list.append([Gtk.STOCK_NO, True, self.device_monitor.connected_devices[device_id][1], self.device_monitor.connected_devices[device_id][0]["Manufacturer"], self.device_monitor.connected_devices[device_id][0]["Product"]]) # Write selected device to file # The device would be kept in a buffer until the program exits def write_to_known_devices(self, button): treeselection = self.treeview.get_selection() model, treeiter = treeselection.get_selected() device = {} if treeiter != None: if model[treeiter][0] == Gtk.STOCK_YES: return if model[treeiter][3]: device["Manufacturer"] = model[treeiter][3] if model[treeiter][4]: device["Product"] = model[treeiter][4] print(device["Product"]) print(device["Manufacturer"]) busnum, devnum = model[treeiter][2].split("\n")[0].split("Bus")[1].split("Address") devnum = devnum.split()[0] dev = usb.core.find(address=int(devnum), bus=int(busnum)) dev_id = read_device.get_descriptors(dev) self.device_monitor.add_to_known_device(dev_id, device, dev) model.set_value(treeiter, 0, Gtk.STOCK_YES) else: dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "A USB device must be selected!") dialog.format_secondary_text("The selected USB device will be written to a 'know_hosts' file") dialog.run() # Remove selected device from file def remove_from_known_devices(self, button): treeselection = self.treeview.get_selection() model, treeiter = treeselection.get_selected() device = {} if treeiter != None: if model[treeiter][0] == Gtk.STOCK_NO: return if model[treeiter][3]: device["Manufacturer"] = model[treeiter][2] if model[treeiter][4]: device["Product"] = model[treeiter][3] busnum, devnum = model[treeiter][2].split("\n")[0].split("Bus")[1].split("Address") devnum = devnum.split()[0] dev = usb.core.find(address=int(devnum), bus=int(busnum)) dev_id = read_device.get_descriptors(dev) self.device_monitor.known_devices.pop(dev_id) model.set_value(treeiter, 0, Gtk.STOCK_NO) else: dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "A USB device must be selected!") dialog.format_secondary_text("The selected USB device was removed") dialog.run() # Check new devices def refresh(self, device): treeselection = self.treeview.get_selection() model, treeiter = treeselection.get_selected() if treeiter != None: index = (model.get_path(treeiter)).get_indices()[0] action = device.action bus_id = device.sys_name if action == 'add': devnum = int(device.attributes.get("devnum")) busnum = int(device.attributes.get("busnum")) dev = usb.core.find(address=devnum, bus=busnum) dev_id = read_device.get_descriptors(dev) dev_name = read_device.get_device_name(device.attributes) self.device_monitor.add_connected_device(bus_id, dev_id, dev_name, dev) if dev_id not in self.device_monitor.known_devices.keys(): self.usb_list.append([Gtk.STOCK_NO, True, str(dev), dev_name["Manufacturer"], dev_name["Product"]]) else: self.usb_list.append([Gtk.STOCK_YES, True, str(dev), dev_name["Manufacturer"], dev_name["Product"]]) if action == 'remove': bus_id = self.device_monitor.remove_connected_device(dev) self.remove_from_usb_list(bus_id) if treeiter != None: self.treeview.set_cursor(index) return True # Remove one entry from the usb_list (to remove from the gtk tree) def remove_from_usb_list(self, bus_id): for entry in self.usb_list: if entry[2] == bus_id: entry.model.remove(entry.iter) break # Tests if the usb is connected, known device or unknown def usb_filter_func(self, model, iter, data): if self.current_filter_usb is None or self.current_filter_usb == "None": return True elif self.current_filter_usb == "Known Devices": return model[iter][0] == Gtk.STOCK_YES elif self.current_filter_usb == "Unknown Devices": return model[iter][0] == False else: return model[iter][1] == True # Called on any of the button clicks def on_selection_button_clicked(self, widget): self.current_filter_usb = widget.get_label() print("{} usb selected!".format(self.current_filter_usb)) self.usb_filter.refilter() def quit_monitor(self): self.device_monitor.usb_monitor_stop() print("The know device list {}".format(self.device_monitor.known_devices))
class UsbStorageMonitor(object): """ USB storage device add monitor This monitor is listening to UDEV for USB storage device 'add' events. The callback that is provided to the constructor is called for every USB storage device that is added to the system. """ def __init__(self, add_callback, remove_callback = None, change_callback = None, for_gui = False): self._logger = logging.getLogger('efalive.UsbStorageMonitor') self._external_add_callback = add_callback self._external_remove_callback = remove_callback self._external_change_callback = change_callback self._udev_context = Context() self._udev_monitor = Monitor.from_netlink(self._udev_context) self._udev_monitor.filter_by('block', device_type='partition') self._for_gui = for_gui if for_gui: self._udev_observer = UdevGuiObserver(self._udev_monitor) self._udev_observer.connect('device-event', self._handle_gui_device_event) else: self._udev_observer = UdevObserver(self._udev_monitor, callback=self._handle_device_event, name='monitor-observer') def start(self): if self._for_gui: self._udev_monitor.start() else: self._udev_observer.start() def stop(self): if self._for_gui: self._udev_monitor.stop() else: self._udev_observer.stop() def _handle_gui_device_event(self, observer, device): self._handle_device_event(device) def _handle_device_event(self, device): self._debug_device(device) if (device.get("ID_BUS") != "usb"): return self._logger.info("Action %s for device %s" % (device.action, device.device_node)) if device.action == "add": wrapped_device = self._wrap_device(device) self._external_add_callback(wrapped_device) elif device.action == "remove" and self._external_remove_callback != None: wrapped_device = self._wrap_device(device) self._external_remove_callback(wrapped_device) elif device.action == "change" and self._external_change_callback != None: wrapped_device = self._wrap_device(device) self._external_change_callback(wrapped_device) else: self._logger.info("Unhandled action: %s" % device.action) def _debug_device(self, device): self._logger.debug("Device:") self._logger.debug("\tSubsystem: %s" % device.subsystem) self._logger.debug("\tType: %s" % device.device_type) self._logger.debug("\tName: %s" % device.sys_name) self._logger.debug("\tNumber: %s" % device.sys_number) self._logger.debug("\tSYS-fs path: %s" % device.sys_path) self._logger.debug("\tDriver: %s" % device.driver) self._logger.debug("\tAction: %s" % device.action) self._logger.debug("\tFile: %s" % device.device_node) #self._logger.debug("\tLinks: %s" % device.get_device_file_symlinks()) #self._logger.debug("\tProperties: %s" % device.get_property_keys()) #self._logger.debug("\tSYBSYSTEM: %s" % device.get_property("SUBSYSTEM")) #self._logger.debug("\tDEVTYPE: %s" % device.get_property("DEVTYPE")) ##self._logger.debug("\tID_VENDOR: %s" % device.get("ID_VENDOR")) self._logger.debug("\tID_SERIAL: %s" % device.properties.get("ID_SERIAL")) self._logger.debug("\tID_MODEL: %s" % device.get("ID_MODEL")) self._logger.debug("\tID_TYPE: %s" % device.get("ID_TYPE")) self._logger.debug("\tID_BUS: %s" % device.get("ID_BUS")) self._logger.debug("\tID_FS_LABEL: %s" % device.get("ID_FS_LABEL")) self._logger.debug("\tID_FS_TYPE: %s" % device.get("ID_FS_TYPE")) self._logger.debug("\tID_PART_ENTRY_SIZE: %s" % device.get("ID_PART_ENTRY_SIZE")) #self._logger.debug("All attributes:") #for attrName in device.__iter__(): # self._logger.debug(attrName) def _wrap_device(self, device): """ Convert a PyUdev device to an efaLive device """ if device is None: return None wrapped_device = UsbStorageDevice(device.device_node) if device.get("ID_VENDOR"): wrapped_device.vendor = device.get("ID_VENDOR") if device.get("ID_MODEL"): wrapped_device.model = device.get("ID_MODEL") if device.get("ID_PART_ENTRY_SIZE"): byte_size = float(device.get("ID_PART_ENTRY_SIZE")) size = byte_size / 1024 unit = "KB" if (size > 1024): size = size / 1024 unit = "MB" if (size > 1024): size = size / 1024 unit = "GB" if (size > 1024): size = size / 1024 unit = "TB" wrapped_device.size = "%.1f %s" % (size, unit) if device.get("ID_FS_TYPE"): wrapped_device.fs_type = device.get("ID_FS_TYPE") if device.get("ID_FS_LABEL"): wrapped_device.label = device.get("ID_FS_LABEL") if device.get("ID_VENDOR_ID") and device.get("ID_MODEL_ID"): wrapped_device.bus_id = "%s:%s" % (device.get("ID_VENDOR_ID"), device.get("ID_MODEL_ID")) if device.properties.get("ID_SERIAL"): wrapped_device.serial = device.properties.get("ID_SERIAL") return wrapped_device def search_for_usb_block_devices(self): for usb_device in self._udev_context.list_devices(subsystem='block', DEVTYPE='partition'): if (usb_device.get("ID_BUS") != "usb"): continue wrapped_device = self._wrap_device(usb_device) self._external_add_callback(wrapped_device)
class RazerDaemon(DBusService): """ Daemon class This class sets up the main run loop which serves DBus messages. The logger is initialised in this module as well as finding and initialising devices. Serves the following functions via DBus * getDevices - Returns a list of serial numbers * enableTurnOffOnScreensaver - Starts/Continues the run loop on the screensaver thread * disableTurnOffOnScreensaver - Pauses the run loop on the screensaver thread """ def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, persistence_file=None, test_dir=None): setproctitle.setproctitle('openrazer-daemon') # pylint: disable=no-member # Expanding ~ as python doesn't do it by default, also creating dirs if needed try: if log_dir is not None: log_dir = os.path.expanduser(log_dir) os.makedirs(log_dir, exist_ok=True) if run_dir is not None: run_dir = os.path.expanduser(run_dir) os.makedirs(run_dir, exist_ok=True) except NotADirectoryError as e: print("Failed to create {}".format(e.filename), file=sys.stderr) sys.exit(1) if config_file is not None: config_file = os.path.expanduser(config_file) if not os.path.exists(config_file): print("Config file {} does not exist.".format(config_file), file=sys.stderr) sys.exit(1) if persistence_file is not None: persistence_file = os.path.expanduser(persistence_file) if not os.path.exists(persistence_file): print("Persistence file {} does not exist.".format(persistence_file), file=sys.stderr) sys.exit(1) self._test_dir = test_dir self._run_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Logging log_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): log_level = logging.DEBUG self.logger = self._create_logger(log_dir, log_level, console_log) self._persistence_file = persistence_file self._persistence = configparser.ConfigParser() self._persistence.status = {"changed": False} self.read_persistence(persistence_file) # Check for plugdev group if not self._check_plugdev_group(): self.logger.critical("User is not a member of the plugdev group") self.logger.critical("Please run the command 'sudo gpasswd -a $USER plugdev' and then reboot!") sys.exit(1) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) super().__init__('/org/razer') self._init_signals() self._main_loop = GLib.MainLoop() # Listen for input events from udev self._init_udev_monitor() # Load Classes self._device_classes = openrazer_daemon.hardware.get_device_classes() self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) self._init_screensaver_monitor() self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods methods = { # interface, method, callback, in-args, out-args ('razer.devices', 'getDevices', self.get_serial_list, None, 'as'), ('razer.devices', 'supportedDevices', self.supported_devices, None, 's'), ('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver, 'b', None), ('razer.devices', 'getOffOnScreensaver', self.get_off_on_screensaver, None, 'b'), ('razer.devices', 'syncEffects', self.sync_effects, 'b', None), ('razer.devices', 'getSyncEffects', self.get_sync_effects, None, 'b'), ('razer.daemon', 'version', self.version, None, 's'), ('razer.daemon', 'stop', self.stop, None, None), } for m in methods: self.logger.debug("Adding {}.{} method to DBus".format(m[0], m[1])) self.add_dbus_method(m[0], m[1], m[2], in_signature=m[3], out_signature=m[4]) self._collecting_udev = False self._collecting_udev_devices = [] self._init_autosave_persistence() # TODO remove self.sync_effects(self._config.getboolean('Startup', 'sync_effects_enabled')) # TODO ====== @dbus.service.signal('razer.devices') def device_removed(self): self.logger.debug("Emitted Device Remove Signal") @dbus.service.signal('razer.devices') def device_added(self): self.logger.debug("Emitted Device Added Signal") def _create_logger(self, log_dir, log_level, want_console_log): """ Initializes a logger and returns it. :param log_dir: If not None, specifies the directory to create the log file in :param log_level: The log level of messages to print :param want_console_log: True if we should print to the console :rtype:logging.Logger """ logger = logging.getLogger('razer') logger.setLevel(log_level) formatter = logging.Formatter('%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Don't propagate to default logger logger.propagate = 0 if want_console_log: console_logger = logging.StreamHandler() console_logger.setLevel(log_level) console_logger.setFormatter(formatter) logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler(log_file, maxBytes=1048576, backupCount=1) # 1 MiB file_logger.setLevel(log_level) file_logger.setFormatter(formatter) logger.addHandler(file_logger) return logger def _check_plugdev_group(self): """ Check if the user is a member of the plugdev group. For the root user, this always returns True :rtype: bool """ if getpass.getuser() == 'root': return True try: return grp.getgrnam('plugdev').gr_gid in os.getgroups() except KeyError: pass return False def _init_udev_monitor(self): self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='hid') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') def _init_screensaver_monitor(self): try: self._screensaver_monitor = ScreensaverMonitor(self) self._screensaver_monitor.monitoring = self._config.getboolean('Startup', 'devices_off_on_screensaver') except dbus.exceptions.DBusException as e: self.logger.error("Failed to init ScreensaverMonitor: {}".format(e)) def _init_autosave_persistence(self): if not self._persistence: self.logger.debug("Persistence unspecified. Will not create auto save thread") return self._autosave_persistence = PersistenceAutoSave(self._persistence, self._persistence_file, self._persistence.status, self.logger, 10, self.write_persistence) self._autosave_persistence.thread = threading.Thread(target=self._autosave_persistence.watch) self._autosave_persistence.thread.daemon = True self._autosave_persistence.thread.start() def _init_signals(self): """ Heinous hack to properly handle signals on the mainloop. Necessary if we want to use the mainloop run() functionality. """ def signal_action(signum): """ Action to take when a signal is trapped """ self.quit(signum) def idle_handler(): """ GLib idle handler to propagate signals """ GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH) def handler(*args): """ Unix signal handler """ signal_action(args[0]) def install_glib_handler(sig): """ Choose a compatible method and install the handler """ unix_signal_add = None if hasattr(GLib, "unix_signal_add"): unix_signal_add = GLib.unix_signal_add elif hasattr(GLib, "unix_signal_add_full"): unix_signal_add = GLib.unix_signal_add_full if unix_signal_add: unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig) else: print("Can't install GLib signal handler!") for sig in signal.SIGINT, signal.SIGTERM, signal.SIGHUP: signal.signal(sig, idle_handler) GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH) def read_config(self, config_file): """ Read in the config file and set the defaults :param config_file: Config file :type config_file: str or None """ # Generate sections as trying to access a value even if a default exists will die if the section does not for section in ('General', 'Startup'): self._config[section] = {} self._config['General'] = { 'verbose_logging': False, } self._config['Startup'] = { 'sync_effects_enabled': True, 'devices_off_on_screensaver': True, 'restore_persistence': True, } if config_file is not None and os.path.exists(config_file): self._config.read(config_file) # Compatibility to older configs if 'mouse_battery_notifier' in self._config['Startup']: self._config['Startup']['battery_notifier'] = self._config['Startup']['mouse_battery_notifier'] if 'mouse_battery_notifier_freq' in self._config['Startup']: self._config['Startup']['battery_notifier_freq'] = self._config['Startup']['mouse_battery_notifier_freq'] def read_persistence(self, persistence_file): """ Read the persistence file and set states into memory :param persistence_file: Persistence file :type persistence_file: str or None """ if persistence_file is not None and os.path.exists(persistence_file): try: self._persistence.read(persistence_file) except configparser.Error: self.logger.warning('Failed to read persistence config, resetting!', exc_info=True) with open(persistence_file, "w") as f: f.writelines("") def write_persistence(self, persistence_file): """ Write in the persistence file :param persistence_file: Persistence file :type persistence_file: str or None """ if not persistence_file: return self.logger.debug('Writing persistence config') for device in self._razer_devices: self._persistence[device.dbus.storage_name] = {} if 'set_dpi_xy' in device.dbus.METHODS or 'set_dpi_xy_byte' in device.dbus.METHODS: dpi_x = int(device.dbus.dpi[0]) dpi_y = int(device.dbus.dpi[1]) # When Y is not greater than 0 check for a DPI X only device, a device with 'available_dpi' and a Y value of 0 if dpi_x > 0 and (dpi_y > 0 or ('available_dpi' in device.dbus.METHODS and dpi_y == 0)): self._persistence[device.dbus.storage_name]['dpi_x'] = str(dpi_x) self._persistence[device.dbus.storage_name]['dpi_y'] = str(dpi_y) if 'set_poll_rate' in device.dbus.METHODS: self._persistence[device.dbus.storage_name]['poll_rate'] = str(device.dbus.poll_rate) for i in device.dbus.ZONES: if device.dbus.zone[i]["present"]: self._persistence[device.dbus.storage_name][i + '_active'] = str(device.dbus.zone[i]["active"]) self._persistence[device.dbus.storage_name][i + '_brightness'] = str(device.dbus.zone[i]["brightness"]) self._persistence[device.dbus.storage_name][i + '_effect'] = device.dbus.zone[i]["effect"] self._persistence[device.dbus.storage_name][i + '_colors'] = ' '.join(str(i) for i in device.dbus.zone[i]["colors"]) self._persistence[device.dbus.storage_name][i + '_speed'] = str(device.dbus.zone[i]["speed"]) self._persistence[device.dbus.storage_name][i + '_wave_dir'] = str(device.dbus.zone[i]["wave_dir"]) with open(persistence_file, 'w') as cf: self._persistence.write(cf) def get_off_on_screensaver(self): """ Returns if turn off on screensaver :return: Result :rtype: bool """ return self._screensaver_monitor.monitoring def enable_turn_off_on_screensaver(self, enable): """ Enable the turning off of devices when the screensaver is active """ self._screensaver_monitor.monitoring = enable def supported_devices(self): result = {cls.__name__: (cls.USB_VID, cls.USB_PID) for cls in self._device_classes} return json.dumps(result) def version(self): """ Get the daemon version :return: Version string :rtype: str """ return __version__ def suspend_devices(self): """ Suspend all devices """ for device in self._razer_devices: device.dbus.suspend_device() def resume_devices(self): """ Resume all devices """ for device in self._razer_devices: device.dbus.resume_device() def get_serial_list(self): """ Get list of devices serials """ serial_list = self._razer_devices.serials() self.logger.debug('DBus called get_serial_list') return serial_list def sync_effects(self, enabled): """ Sync the effects across the devices :param enabled: True to sync effects :type enabled: bool """ # Todo perhaps move logic to device collection for device in self._razer_devices.devices: device.dbus.effect_sync = enabled def get_sync_effects(self): """ Sync the effects across the devices :return: True if any devices sync effects :rtype: bool """ result = False for device in self._razer_devices.devices: result |= device.dbus.effect_sync return result def _load_devices(self, first_run=False): """ Go through supported devices and load them Loops through the available hardware classes, loops through each device in the system and adds it if needs be. """ if first_run: # Just some pretty output max_name_len = max([len(cls.__name__) for cls in self._device_classes]) + 2 for cls in self._device_classes: format_str = 'Loaded device specification: {0:-<' + str(max_name_len) + '} ({1:04x}:{2:04X})' self.logger.debug(format_str.format(cls.__name__ + ' ', cls.USB_VID, cls.USB_PID)) if self._test_dir is not None: device_list = os.listdir(self._test_dir) test_mode = True else: device_list = list(self._udev_context.list_devices(subsystem='hid')) test_mode = False device_number = 0 for device in device_list: for device_class in self._device_classes: # Interoperability between generic list of 0000:0000:0000.0000 and pyudev if test_mode: sys_name = device sys_path = os.path.join(self._test_dir, device) else: sys_name = device.sys_name sys_path = device.sys_path if sys_name in self._razer_devices: continue if device_class.match(sys_name, sys_path): # Check it matches sys/ ID format and has device_type file self.logger.info('Found device.%d: %s', device_number, sys_name) # TODO add testdir support # Basically find the other usb interfaces device_match = sys_name.split('.')[0] additional_interfaces = [] if not test_mode: double_device = False for alt_device in self._razer_devices: if device_match in alt_device.device_id and alt_device.device_id != sys_name and sys_path in alt_device.dbus.additional_interfaces: self.logger.warning('BUG: Device %s has already been found with interface %s. Skipping', sys_name, alt_device.device_id) double_device = True if double_device: continue for alt_device in device_list: if device_match in alt_device.sys_name and alt_device.sys_name != sys_name: additional_interfaces.append(alt_device.sys_path) # Checking permissions test_file = os.path.join(sys_path, 'device_type') file_group_id = os.stat(test_file).st_gid file_group_name = grp.getgrgid(file_group_id)[0] if os.getgid() != file_group_id and file_group_name != 'plugdev': self.logger.critical("Could not access {0}/device_type, file is not owned by plugdev".format(sys_path)) break razer_device = device_class(device_path=sys_path, device_number=device_number, config=self._config, persistence=self._persistence, testing=self._test_dir is not None, additional_interfaces=sorted(additional_interfaces), additional_methods=[]) # Wireless devices sometimes don't listen count = 0 while count < 3: # Loop to get serial, exit early if it gets one device_serial = razer_device.get_serial() if len(device_serial) > 0: break time.sleep(0.1) count += 1 else: logging.warning("Could not get serial for device {0}. Skipping".format(sys_name)) continue self._razer_devices.add(sys_name, device_serial, razer_device) device_number += 1 def _add_device(self, device): """ Add device event from udev :param device: Udev Device :type device: pyudev.device._device.Device """ device_number = len(self._razer_devices) for device_class in self._device_classes: sys_name = device.sys_name sys_path = device.sys_path if sys_name in self._razer_devices: continue if device_class.match(sys_name, sys_path): # Check it matches sys/ ID format and has device_type file self.logger.info('Found valid device.%d: %s', device_number, sys_name) razer_device = device_class(device_path=sys_path, device_number=device_number, config=self._config, persistence=self._persistence, testing=self._test_dir is not None, additional_interfaces=None, additional_methods=[]) # Its a udev event so currently the device hasn't been chmodded yet time.sleep(0.2) # Wireless devices sometimes don't listen device_serial = razer_device.get_serial() if len(device_serial) > 0: # Add Device self._razer_devices.add(sys_name, device_serial, razer_device) self.device_added() else: logging.warning("Could not get serial for device {0}. Skipping".format(sys_name)) else: # Basically find the other usb interfaces device_match = sys_name.split('.')[0] for d in self._razer_devices: if device_match in d.device_id and d.device_id != sys_name: if not sys_path in d.dbus.additional_interfaces: d.dbus.additional_interfaces.append(sys_path) return def _remove_device(self, device): """ Remove device event from udev :param device: Udev Device :type device: pyudev.device._device.Device """ device_id = device.sys_name try: device = self._razer_devices[device_id] device.dbus.close() device.dbus.remove_from_connection() self.write_persistence(self._persistence_file) self.logger.warning("Removing %s", device_id) # Delete device del self._razer_devices[device.device_id] self.device_removed() except IndexError: # Why didn't i set it up as KeyError # It will return "extra" events for the additional usb interfaces bound to the driver pass def _udev_input_event(self, device): """ Function called by the Udev monitor (#observerPattern) :param device: Udev device :type device: pyudev.device._device.Device """ self.logger.debug('Device event [%s]: %s', device.action, device.device_path) if device.action == 'add': if self._collecting_udev: self._collecting_udev_devices.append(device) return else: self._collecting_udev_devices = [device] self._collecting_udev = True t = threading.Thread(target=self._collecting_udev_method, args=(device,)) t.start() elif device.action == 'remove': self._remove_device(device) def _collecting_udev_method(self, device): time.sleep(2) # delay to let udev add all devices that we want # Sort the devices self._collecting_udev_devices.sort(key=lambda x: x.sys_path, reverse=True) for d in self._collecting_udev_devices: self._add_device(d) self._collecting_udev = False def run(self): """ Run the daemon """ self.logger.info('Serving DBus') # Start listening for device changes self._udev_observer.start() # Start the mainloop try: self._main_loop.run() except KeyboardInterrupt: self.logger.debug('Shutting down') def stop(self): """ Wrapper for quit """ self.quit(None) def quit(self, signum): """ Quit by stopping the main loop, observer, and screensaver thread """ # pylint: disable=unused-argument if signum is None: self.logger.info('Stopping daemon.') else: self.logger.info('Stopping daemon on signal %d', signum) self._main_loop.quit() # Stop udev monitor self._udev_observer.send_stop() for device in self._razer_devices: device.dbus.close() # Write config self.write_persistence(self._persistence_file)
class USB_inhibit: # Create context context = Context() # Create monitor monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='usb', device_type='usb_device') name_device = ["Manufacturer", "Product"] MASS_STORAGE = 0x8 HID = 0x03 AUDIO = 0x01 VIDEO = 0x0E device_class_nonblock = [0x09] # Allow USB hubs to connect # Class initializer def __init__(self, flag_known_devices): # Devices that where connected when the usb_inhibit started # -- used for the option when the known_devices flag is False self.connected_devices = {} self.busID_key_map = {} # Device that are connected after the usb_inhibit started # -- used for the option when the known_devices flag is either False or # True -- currently not used self.after_connect = {} # Known devices -- loaded from file self.known_devices = {} # If the devices must remain unseen after the usb-inhibit stops self.flag_remain_seen = False self.flag_known_devices = flag_known_devices self.check_args() # Validate the command def check_args(self): self.running_mode_cont = False self.process = None # Eg. usb-inhibit -u -- sleep 10 try: index = sys.argv.index('--') # --> 2 # Check if block if sys.argv[index+1:][0] == "allow": try: self.device_class_nonblock = [int(x, 0) for x in sys.argv[index+1:][1:]] except ValueError: sys.exit("Invalid arguments for allow - use only valid device classes") self.running_mode_cont = True return # The process self.process = sys.argv[index+1:] # --> sleep 10 # The usb-inhibit parameters parameters = sys.argv[1:index] # --> -u except ValueError: self.running_mode_cont = True parameters = sys.argv[1:] if '-help' in parameters: self.usage() sys.exit(0) if '-u' in parameters: self.flag_remain_seen = True # The proper way to use the usb-inhibit def usage(self): print("USB-inhibit\n" "Call:\n" "\t python usb-inhibit.py -- allow 0x1 0x8\n" "\t python usb-inhibit.py -- process_with_arguments\n" "\t python usb-inhibit.py (continuous inhibitor)\n" "Options:\n" "\t -u -- unseen, after the program finishes running leave " "the USB devices drivers (that were connected during\n" "\t\tthe program execution) unloaded\n" "\t -help -- how to use the python script") # Look for already connected devices and take their bus_id # !!! Not used !!! def form_initial_devices(self): for device in self.context.list_devices(subsystem='usb', DEVTYPE='usb_device'): bus_id = device.sys_name if device.find_parent(subsystem='usb', device_type='usb_device') != None: print(bus_id) (dev_name, key) = self.extract_information(device) self.add_connected_device(bus_id, dev_name, key) # Add a new connected device def add_connected_device(self, bus_id, dev_name, dev_id): self.connected_devices[bus_id] = [dev_name, dev_id] # Remove a connected device using the bus_id def remove_connected_device(self, bus_id): key = "" if bus_id in self.busID_key_map.keys(): key = self.busID_key_map.pop(bus_id) return key # Form the known devices dictionary def get_known_devices(self): if os.path.isfile('../USB_devices/known_devices'): with open('../USB_devices/known_devices', 'rt') as f_in: try: self.known_devices = json.load(f_in) except ValueError: self.known_devices = {} # Start a process def start_process(self): try: pid = subprocess.Popen(self.process) except OSError: pid = None return pid # Rebind the devices that were disconnected (called when the inhibit is # stopped) def rebind_devices(self): with open('/sys/bus/usb/drivers_autoprobe', 'wt') as f_out: f_out.write("1") # If the flag_remain_seen is set then rebind all the still connected # devices that were connected during the usb-inhibit process if not self.flag_remain_seen: for dev in self.busID_key_map.keys(): print("Rebind devie: {}".format(dev)) usb_on.usb_enable(dev) # Stop the usb-inhibit program def stop(self): print("Stop monitoring...") self.rebind_devices() if self.observer != None: self.observer.stop() # For the dbus part we have to clear all the dict content self.known_devices.clear() self.connected_devices.clear() self.busID_key_map.clear() # Start the usb-inhibit program def start(self): self.observer = MonitorObserver(self.monitor, callback = self.start_monitor, name='monitor-usb-inhibitor') # For the lock screen (the usb inhibit will continue to run until # a signal is received -- that would tell the screen unlocked) # Form the dict with the known devices if self.flag_known_devices: self.get_known_devices() # Initial devices not formed - currently not used #self.form_initial_devices() with open('/sys/bus/usb/drivers_autoprobe', 'wt') as f_out: f_out.write("0") print("Start monitoring!") if not self.running_mode_cont: proc = self.start_process() print ("Runs with a given command mode") self.observer.start() while proc.poll() is None: continue # For continuous mode must be called manually the stop command else: # For testing purposes one can let False and then run the inhibit # in continuous mode to see the output of it self.observer.daemon = False self.observer.start() print("Runs in continuous mode") def add_nonblock_device(self, class_dev): self.device_class_non_block.append(class_dev) # Start monitoring def start_monitor(self, device): bus_id = device.sys_name action = device.action # If a new device is added: # * add it to the connected device dict # * check if the flag for known_devices is on and the devic # is in the known devices dict if action == 'add': devnum = int(device.attributes.get("devnum")) busnum = int(device.attributes.get("busnum")) dev = usb.core.find(address=devnum, bus=busnum) dev_id = read_device.get_descriptors(dev) dev_name = read_device.get_device_name(device.attributes) self.add_connected_device(bus_id, dev_name, dev_id) print("Device added!") print("Device name {}, dev_id {} and bus_id {}".format(dev_name, dev_id, bus_id)) # If a device is removed, simply remove it from the # connected device dict if action == 'remove': print("Device removed!") print("Device bus {}".format(bus_id)) self.remove_connected_device(bus_id) # Bind the driver of a device def bind_driver(self, bus_id, dev_id): print (self.connected_devices) if bus_id not in self.connected_devices.keys(): return False if self.connected_devices[bus_id][1] == dev_id: usb_on.usb_enable(bus_id) return True return False
def _run(self): self._stop_event = pipe.Pipe.open() MonitorObserver.run(self)
elif (action == 'remove') and (device.get('ID_INPUT_KEYBOARD') == '1'): print('Keyboard: input remove') # def key_input(key_pressed): # """Handles keyboard release""" # print('Keyboard Control: Key released: ' + key_pressed.name) # if key_pressed.name == 'space': # print('shit') async def keyboard_event(device): try: async for event in device.async_read_loop(): if event.type == ecodes.EV_KEY: print(ecodes.KEY[event.code]) except Exception as ex: print('bum: ' + str(ex)) loop = asyncio.get_event_loop() # Create a context, create monitor at kernel level, select devices context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='input') observer = MonitorObserver(monitor, usb_event_callback, name="keyboard") observer.start() while 1: time.sleep(10)
def __init__(self, args: List[str]): """ At the moment the very, very long initialization of the main window, setting up everything. :param default_path: Use a user defined path as entrypoint. If it's empty, the home directory of the current user will be used. :type default_path: str """ super(tfm, self).__init__() self.setupUi(self) self.setWindowIcon(QIcon.fromTheme('system-file-manager')) self.clipboard = QApplication.clipboard() self.marked_to_cut = [] self.back_stack = stack() self.forward_stack = stack() self.config_dir = os.path.join( QStandardPaths.writableLocation( QStandardPaths().ConfigLocation), type(self).__name__) self.current_path = utility.handle_args(args) self.default_path = self.current_path self.threadpool = QThreadPool() # MAIN VIEW # # set up QFileSystemModel self.filesystem = QFileSystemModel() self.filesystem.setRootPath(self.current_path) self.filesystem.setReadOnly(False) # connect QFileSystemModel to View self.table_view.setModel(self.filesystem) self.table_view.setRootIndex( self.filesystem.index(self.current_path)) # set up header self.horizontal_header = self.table_view.horizontalHeader() self.horizontal_header.setSectionsMovable(True) # name self.horizontal_header.resizeSection(0, 200) # size self.horizontal_header.resizeSection(1, 100) # type self.horizontal_header.resizeSection(2, 100) # FS TREE # # create seperate FileSystemModel for the fs tree self.fs_tree_model = QFileSystemModel() self.fs_tree_model.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot) self.fs_tree_model.setRootPath(QDir.rootPath()) # connect model to view self.fs_tree.setModel(self.fs_tree_model) # hide unneeded columns for column in range(1, self.fs_tree.header().count()): self.fs_tree.hideColumn(column) # expand root item self.fs_tree.expand(self.fs_tree_model.index(0, 0)) # BOOKMARKS # self.bookmarks = bm(path_to_bookmark_file=os.path.join(self.config_dir, 'bookmarks')) self.bookmark_view.setModel(self.bookmarks) # MOUNTS # self.udev_context = Context() self.mounts = mounts_model(context=self.udev_context) self.mounts_view.setModel(self.mounts) udev_monitor = Monitor.from_netlink(self.udev_context) udev_monitor.filter_by(subsystem='block', device_type='partition') udev_observer = MonitorObserver(udev_monitor, self.devices_changed) udev_observer.start() # STATUSBAR # # TODO: dir info self.item_info = QLabel() # self.dir_info = QLabel() self.part_info = QLabel() self.statusbar.addPermanentWidget(self.item_info) # self.statusbar.addPermanentWidget(self.dir_info) self.statusbar.addPermanentWidget(self.part_info) self.part_info.setText(utility.part_info(self.current_path)) # TOOLBAR # # initially disable back/forward navigation self.action_back.setEnabled(False) self.action_forward.setEnabled(False) # main menu self.main_menu = QMenu() self.main_menu.addAction(self.action_show_hidden) self.menu_button = QToolButton() self.menu_button.setMenu(self.main_menu) self.menu_button.setPopupMode(QToolButton().InstantPopup) self.menu_button.setDefaultAction(self.action_menu) self.toolbar.insertWidget(self.action_back, self.menu_button) # adress bar self.adressbar = QLineEdit() self.adressbar.setText(self.current_path) self.toolbar.insertWidget(self.action_go, self.adressbar) # menu for new file or directory self.new_menu = QMenu() self.new_menu.addAction(self.action_new_dir) self.new_menu.addAction(self.action_new_file) self.new_button = QToolButton() self.new_button.setMenu(self.new_menu) self.new_button.setPopupMode(QToolButton().MenuButtonPopup) self.new_button.setDefaultAction(self.action_new_dir) self.toolbar.insertWidget(self.action_back, self.new_button) self.connect_actions_to_events() self.set_shortcuts() self.set_icons() self.set_context_menus()
# https://pyudev.readthedocs.io/en/v0.14/api/monitor.html#pyudev.MonitorObserver from pyudev import Context, Monitor, MonitorObserver from time import sleep context = Context() monitor = Monitor.from_netlink(context) monitor.filter_by(subsystem='input') def print_device_event(action, device): print('background event {0}: {1}'.format(action, device)) observer = MonitorObserver(monitor, print_device_event, name='monitor-observer') print('Starting obverver') observer.start() while True: sleep(600)
class RazerDaemon(DBusService): """ Daemon class This class sets up the main run loop which serves DBus messages. The logger is initialised in this module as well as finding and initialising devices. Serves the following functions via DBus * getDevices - Returns a list of serial numbers * enableTurnOffOnScreensaver - Starts/Continues the run loop on the screensaver thread * disableTurnOffOnScreensaver - Pauses the run loop on the screensaver thread """ BUS_PATH = 'org.razer' def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, test_dir=None): # Check if process exists exit_code = subprocess.call(['pgrep', 'razer-service'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) if exit_code == 0: print("Daemon already exists. Please stop that one.", file=sys.stderr) exit(-1) setproctitle.setproctitle('razer-service') # Expanding ~ as python doesnt do it by default, also creating dirs if needed if log_dir is not None: log_dir = os.path.expanduser(log_dir) os.makedirs(log_dir, mode=0o750, exist_ok=True) if run_dir is not None: run_dir = os.path.expanduser(run_dir) os.makedirs(run_dir, mode=0o750, exist_ok=True) if config_file is not None: config_file = os.path.expanduser(config_file) os.makedirs(os.path.dirname(config_file), mode=0o750, exist_ok=True) self._test_dir = test_dir self._data_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) DBusService.__init__(self, self.BUS_PATH, '/org/razer') self._init_signals() self._main_loop = GObject.MainLoop() # Listen for input events from udev self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='input') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') # Logging logging_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): logging_level = logging.DEBUG self.logger = logging.getLogger('razer') self.logger.setLevel(logging_level) formatter = logging.Formatter( '%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Dont propagate to default logger self.logger.propagate = 0 if console_log: console_logger = logging.StreamHandler() console_logger.setLevel(logging_level) console_logger.setFormatter(formatter) self.logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler( log_file, maxBytes=16777216, backupCount=10) # 16MiB file_logger.setLevel(logging_level) file_logger.setFormatter(formatter) self.logger.addHandler(file_logger) self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) # Setup screensaver thread self._screensaver_thread = ScreensaverThread( self, active=self._config.getboolean('Startup', 'devices_off_on_screensaver')) self._screensaver_thread.start() self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods self.logger.info("Adding razer.devices.getDevices method to DBus") self.add_dbus_method('razer.devices', 'getDevices', self.get_serial_list, out_signature='as') self.logger.info( "Adding razer.devices.enableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver) self.logger.info( "Adding razer.devices.disableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'disableTurnOffOnScreensaver', self.disable_turn_off_on_screensaver) self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'syncEffects', self.sync_effects, in_signature='b') self.logger.info("Adding razer.daemon.version method to DBus") self.add_dbus_method('razer.daemon', 'version', self.version, out_signature='s') self.logger.info("Adding razer.daemon.stop method to DBus") self.add_dbus_method('razer.daemon', 'stop', self.stop) # TODO remove self.sync_effects( self._config.getboolean('Startup', 'sync_effects_enabled')) # TODO ====== def _init_signals(self): """ Heinous hack to properly handle signals on the mainloop. Necessary if we want to use the mainloop run() functionality. """ def signal_action(signum): """ Action to take when a signal is trapped """ self.quit(signum) def idle_handler(): """ GLib idle handler to propagate signals """ GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH) def handler(*args): """ Unix signal handler """ signal_action(args[0]) def install_glib_handler(sig): """ Choose a compatible method and install the handler """ unix_signal_add = None if hasattr(GLib, "unix_signal_add"): unix_signal_add = GLib.unix_signal_add elif hasattr(GLib, "unix_signal_add_full"): unix_signal_add = GLib.unix_signal_add_full if unix_signal_add: unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig) else: print("Can't install GLib signal handler!") for sig in signal.SIGINT, signal.SIGTERM, signal.SIGHUP: signal.signal(sig, idle_handler) GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH) def read_config(self, config_file): """ Read in the config file and set the defaults :param config_file: Config file :type config_file: str or None """ # Generate sections as trying to access a value even if a default exists will die if the section does not for section in ('General', 'Startup', 'Statistics'): self._config[section] = {} self._config['DEFAULT'] = { 'verbose_logging': True, 'sync_effects_enabled': True, 'devices_off_on_screensaver': True, 'key_statistics': False, } if config_file is not None and os.path.exists(config_file): self._config.read(config_file) def enable_turn_off_on_screensaver(self): """ Enable the turning off of devices when the screensaver is active """ self._screensaver_thread.active = True def disable_turn_off_on_screensaver(self): """ Disable the turning off of devices when the screensaver is active """ self._screensaver_thread.active = False def version(self): """ Get the daemon version :return: Version string :rtype: str """ return __version__ def suspend_devices(self): """ Suspend all devices """ for device in self._razer_devices: device.dbus.suspend_device() def resume_devices(self): """ Resume all devices """ for device in self._razer_devices: device.dbus.resume_device() def get_serial_list(self): """ Get list of devices serials """ serial_list = self._razer_devices.serials() self.logger.debug('DBus called get_serial_list') return serial_list def sync_effects(self, enabled): """ Sync the effects across the devices :param enabled: True to sync effects :type enabled: bool """ # Todo perhaps move logic to device collection for device in self._razer_devices.devices: device.dbus.effect_sync = enabled def _load_devices(self, first_run=False): """ Go through supported devices and load them Loops through the available hardware classes, loops through each device in the system and adds it if needs be. """ classes = razer_daemon.hardware.get_device_classes() if first_run: # Just some pretty output max_name_len = max([len(cls.__name__) for cls in classes]) + 2 for cls in classes: format_str = 'Loaded device specification: {0:-<' + str( max_name_len) + '} ({1:04x}:{2:04X})' self.logger.debug( format_str.format(cls.__name__ + ' ', cls.USB_VID, cls.USB_PID)) for device in self._udev_context.list_devices(subsystem='hid'): device_number = 0 for device_class in classes: if device.sys_name in self._razer_devices: continue if device_class.match( device.sys_name, device.parent.sys_path ): # Check it matches sys/ ID format and has device_type file self.logger.info('Found device.%d: %s', device_number, device.sys_name) razer_device = device_class(device.sys_path, device_number, self._config, testing=self._test_dir is not None) # Wireless devices sometimes dont listen count = 0 while count < 3: # Loop to get serial, exit early if it gets one device_serial = razer_device.get_serial() if len(device_serial) > 0: break count += 1 else: logging.warning( "Could not get serial for device {0}. Skipping". format(device.sys_name)) continue self._razer_devices.add(device.sys_name, device_serial, razer_device) device_number += 1 def _remove_devices(self): """ Go through the list of current devices and if they no longer exist then remove them """ hid_devices = [ dev.sys_name for dev in self._udev_context.list_devices(subsystem='hid') ] devices_to_remove = [ dev for dev in self._razer_devices if dev not in hid_devices ] for device in devices_to_remove: if self._test_dir is not None: # Remove from DBus device.dbus.remove_from_connection() # Remove device self.logger.warning("Device %s is missing. Removing from DBus", device.device_id) del self._razer_devices[device.device_id] def _udev_input_event(self, device): self.logger.debug('Device event [%s]: %s', device.action, device.device_path) if device.action == 'add': self._load_devices() elif device.action == 'remove': self._remove_devices() def run(self): """ Run the daemon """ self.logger.info('Serving DBus') # Start listening for device changes self._udev_observer.start() # Start the mainloop try: self._main_loop.run() except KeyboardInterrupt: self.logger.debug('Shutting down') def stop(self): """ Wrapper for quit """ self.quit(None) def quit(self, signum): """ Quit by stopping the main loop, observer, and screensaver thread """ # pylint: disable=unused-argument if signum is None: self.logger.info('Stopping daemon.') else: self.logger.info('Stopping daemon on signal %d', signum) self._main_loop.quit() # Stop udev monitor self._udev_observer.send_stop() # Stop screensaver self._screensaver_thread.shutdown = True self._screensaver_thread.join(timeout=2) if self._screensaver_thread.is_alive(): self.logger.warning('Could not stop the screensaver thread') for device in self._razer_devices: device.dbus.close()
def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, test_dir=None): # Check if process exists and is not running as current user proc = subprocess.Popen(['pgrep', 'razer-daemon'], stderr=subprocess.DEVNULL, stdout=subprocess.PIPE) stdout = proc.communicate()[0] # If 0 there are other services running if proc.returncode == 0: current_uid = str(os.getuid()) # Loop through other running daemon's pids = stdout.decode().strip('\n').split('\n') for pid in pids: # Open status file in /proc to get uid with open('/proc/{0}/status'.format(pid), 'r') as status_file: for line in status_file: # Looking for # Uid: 1000 1000 1000 1000 # If they match current pid, then we have a daemon running as this user if line.startswith('Uid:') and line.strip( '\n').split()[-1] == current_uid: print( "Daemon already exists. Please stop that one.", file=sys.stderr) sys.exit(-1) setproctitle.setproctitle('razer-daemon') # Expanding ~ as python doesnt do it by default, also creating dirs if needed if log_dir is not None: log_dir = os.path.expanduser(log_dir) if run_dir is not None: run_dir = os.path.expanduser(run_dir) if config_file is not None: config_file = os.path.expanduser(config_file) self._test_dir = test_dir self._run_dir = run_dir self._config_file = config_file self._config = configparser.ConfigParser() self.read_config(config_file) # Setup DBus to use gobject main loop dbus.mainloop.glib.threads_init() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) DBusService.__init__(self, self.BUS_PATH, '/org/razer') self._init_signals() self._main_loop = GObject.MainLoop() # Listen for input events from udev self._udev_context = Context() udev_monitor = Monitor.from_netlink(self._udev_context) udev_monitor.filter_by(subsystem='hid') self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') # Logging logging_level = logging.INFO if verbose or self._config.getboolean('General', 'verbose_logging'): logging_level = logging.DEBUG self.logger = logging.getLogger('razer') self.logger.setLevel(logging_level) formatter = logging.Formatter( '%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Dont propagate to default logger self.logger.propagate = 0 if console_log: console_logger = logging.StreamHandler() console_logger.setLevel(logging_level) console_logger.setFormatter(formatter) self.logger.addHandler(console_logger) if log_dir is not None: log_file = os.path.join(log_dir, 'razer.log') file_logger = logging.handlers.RotatingFileHandler( log_file, maxBytes=16777216, backupCount=10) # 16MiB file_logger.setLevel(logging_level) file_logger.setFormatter(formatter) self.logger.addHandler(file_logger) # Load Classes self._device_classes = razer_daemon.hardware.get_device_classes() self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) # Check for plugdev group try: plugdev_group = grp.getgrnam('plugdev') if getpass.getuser() not in plugdev_group.gr_mem: self.logger.critical( "User is not a member of the plugdev group") sys.exit(1) except KeyError: self.logger.warning( "Could not check if user is a member of the plugdev group. Continuing..." ) self._screensaver_monitor = ScreensaverMonitor(self) self._screensaver_monitor.monitoring = self._config.getboolean( 'Startup', 'devices_off_on_screensaver') self._razer_devices = DeviceCollection() self._load_devices(first_run=True) # Add DBus methods self.logger.info("Adding razer.devices.getDevices method to DBus") self.add_dbus_method('razer.devices', 'getDevices', self.get_serial_list, out_signature='as') self.logger.info("Adding razer.daemon.supportedDevices method to DBus") self.add_dbus_method('razer.daemon', 'supportedDevices', self.supported_devices, out_signature='s') self.logger.info( "Adding razer.devices.enableTurnOffOnScreensaver method to DBus") self.add_dbus_method('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver, in_signature='b') self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'getOffOnScreensaver', self.get_off_on_screensaver, out_signature='b') self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'syncEffects', self.sync_effects, in_signature='b') self.logger.info("Adding razer.devices.syncEffects method to DBus") self.add_dbus_method('razer.devices', 'getSyncEffects', self.get_sync_effects, out_signature='b') self.logger.info("Adding razer.daemon.version method to DBus") self.add_dbus_method('razer.daemon', 'version', self.version, out_signature='s') self.logger.info("Adding razer.daemon.stop method to DBus") self.add_dbus_method('razer.daemon', 'stop', self.stop) # TODO remove self.sync_effects( self._config.getboolean('Startup', 'sync_effects_enabled'))
def __init__(self, obj, devname, refresh=0, baudrate=115200, bytesize=8, parity='N', stopbits=2, timeout=400, debug=False, window_size=8, rx_window_size=16, transport_fifo_size=100, ack_retransmit_timeout_ms=25, frame_retransmit_timeout_ms=50): # Name and type of the connection peer self.name = '' self.type = '' self._devname = devname self.object = obj self.baudrate = baudrate self.bytesize = bytesize self.parity = parity self.stopbits = stopbits self.timeout = timeout self.transport_fifo_size = transport_fifo_size self.ack_retransmit_timeout_ms = ack_retransmit_timeout_ms self.max_window_size = window_size self.frame_retransmit_timeout_ms = frame_retransmit_timeout_ms self.rx_window_size = rx_window_size # State of transport FIFO self._transport_fifo = None self._last_sent_ack_time_ms = None # State for receiving a MIN frame self._rx_frame_buf = bytearray() self._rx_header_bytes_seen = 0 self._rx_frame_state = self.SEARCHING_FOR_SOF self._rx_frame_checksum = 0 self._rx_frame_id_control = 0 self._rx_frame_seq = 0 self._rx_frame_length = 0 self._rx_control = 0 self._stashed_rx_dict = {} self._rn = 0 # Sequence number expected to be received next self._sn_min = 0 # Sequence number of first frame currently in the sending window self._sn_max = 0 # Next sequence number to use for sending a frame self.source = {} # sequence <--> sommand source linking self._nack_outstanding = None self._transport_fifo_reset() if refresh > 0: self._refresh = refresh self._updateTimer = LoopingCall(self.update) self._updateTimer.start(self._refresh) context = Context() for device in context.list_devices(subsystem='tty'): if 'DEVLINKS' in device.keys() and self._devname in device.get( 'DEVLINKS'): self.Connect() self.connectionMade() cm = Monitor.from_netlink(context) cm.filter_by(subsystem='tty') observer = MonitorObserver(cm, callback=self.ConnectionMCallBack, name='monitor-observer') observer.start()
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): ttyDeviceEvent = pyqtSignal(str) def __init__(self, *args, **kwargs): QtWidgets.QMainWindow.__init__(self, *args, **kwargs) self.setupUi(self) self.threadpool=QThreadPool() #Controller to manage Arduino self.arduinoController=arduinoController(self.threadpool) self.selectedPort='' #TODO conect arduinoController signals to MainWindow slots #levantamos el detector de coneccion/desconeccion self.context = Context() self.monitor = Monitor.from_netlink(self.context) self.monitor.filter_by(subsystem='tty') self.observer = MonitorObserver(self.monitor, callback=self.eventDetected, name='monitor-observer') self.observer.daemon self.observer.start() self.ttyDeviceEvent.connect(self.onTtyDeviceEvent) logger.info("MonitorObserver started") self.onLoadWindow() def onLoadWindow(self): portList=list_ports.comports() for port in portList: portAction = QtWidgets.QAction(port.device,self) portAction.setCheckable(True) self.menuPuertos.addAction(portAction) self.actionSeleccionarPuerto.setEnabled(False) self.enviarComando.clicked.connect(self.sendCommand) self.conectarArduino.setEnabled(False) self.menuPuertos.triggered.connect(self.onPortClicked) self.conectarArduino.triggered.connect(self.arduinoController.connectArduino) def sendCommand(self): text=self.comando.text() logger.debug("Enviando comando:"+text) def removePorts(self): logger.debug("TODO: Remove ports on arduinoEventDetected") self.checkConnection() @pyqtSlot(QtWidgets.QAction) def onPortClicked(self,port): logger.info('Port: {} - check status: {}'.format(port.text(),port.isChecked())) if port.isChecked(): self.selectedPort=port.text() self.menuPuertos.setTitle('Puerto: {}'.format(self.selectedPort)) for actionItem in self.menuPuertos.actions(): if actionItem.text()!=self.selectedPort: actionItem.setChecked(False) else: if self.selectedPort==port.text(): self.selectedPort="" self.menuPuertos.setTitle('Puerto') logger.info('Selected port: {}'.format(self.selectedPort)) @pyqtSlot(str) def onTtyDeviceEvent(self,action): if action =="added": portList=list_ports.comports() for port in portList: portAction = QtWidgets.QAction(port.device,self) portAction.setCheckable(True) isPresent = False; for actionItem in self.menuPuertos.actions(): if actionItem.text()==port.device: logger.info("Port added already present") isPresent=True if isPresent==False: logger.info("New port added") self.menuPuertos.addAction(portAction) elif action =="removed": logger.info("Do something on removed device") if self.arduinoController.isConnected()==False: logger.info("Arduino not conected") self.removePorts() portList=list_ports.comports()]\ nothingSelected = True for port in portList: portAction = QtWidgets.QAction(port.device,self) portAction.setCheckable(True) if self.selectedPort==port.device: nothingSelected = False logger.info("Reload selected port") portAction.setChecked(True) self.menuPuertos.addAction(portAction) if nothingSelected==True: self.selectedPort="" self.menuPuertos.setTitle('Puerto') logger.info('Selected port: {}'.format(self.selectedPort)) #Este evento se dispara en el MonitorObserver Thread def eventDetected(self,device): logger.info('Event detected - DEVICE: {0} - ACTION: {0.action}'.format(device)) if device.action =="add": self.ttyDeviceEvent.emit("added") if device.action =="remove": self.ttyDeviceEvent.emit("removed") def removePorts(self): self.menuPuertos.clear() actionSeleccionarPuerto = QtWidgets.QAction("Seleccionar Puerto",self) actionSeleccionarPuerto.setEnabled(False) font = QtGui.QFont() actionSeleccionarPuerto.setFont(font) actionSeleccionarPuerto.setObjectName("actionSeleccionarPuerto") actionSeleccionarPuerto.setText("Seleccionar Puerto") self.menuPuertos.addAction(actionSeleccionarPuerto)