#!/usr/bin/env python from argparse import RawTextHelpFormatter from colour import Color from openrazer.client import DeviceManager from pathlib import Path import argparse import os import time import toml def print_logo(): logo = """ _ _ _ /\ \ /\ \ /\ \ / \ \ / \ \ / \ \ / /\ \ \ __/ /\ \ \ / /\ \ \ / / /\ \_\/___/ /\ \ \ / / /\ \_\ / / /_/ / /\___\/ / / / / / /_/ / / / / /__\/ / / / / / / /__\/ / / / /_____/ / / / _ / / /_____/ / / /\ \ \ \ \ \__/\_\ / / /\ \ \ / / / \ \ \ \ \___\/ // / / \ \ \ \/_/ \_\/ \/___/_/ \/_/ \_\/ """ print(logo) def error(msg): print("ERROR: {}".format(msg)) def get_color_tuple(color_string): # Convert color string to RGB tuple try: color = Color(color_string).rgb except: raise Exception("'{}' is not a valid color".format(color_string)) # Scale RGB tuple from [0, 1] to [0, 255] color_tuple = tuple(map(lambda x: int(x * 255), color)) return color_tuple def apply_lightmap(device_profile): global device_manager, lightmap_directory # Get openrazer device device = next( ( d for d in device_manager.devices if d.name.lower().strip() == device_profile["name"].lower().strip() ), None, ) if not device: error("device '{}' not available".format(device_profile["name"])) exit(1) # Open lightmap try: lightmap = toml.load( "{}/{}.toml".format(lightmap_directory, device_profile["lightmap"]) ) except FileNotFoundError: error( "the lightmap '{}' for device '{}' doesn't exist".format( device_profile["lightmap"], device_profile["name"] ) ) list_lightmaps() exit(1) except Exception as e: error( "failed to load lightmap '{}' for device '{}': {}".format( device_profile["lightmap"], device_profile["name"], e ) ) exit(1) # Set light colors try: for light in device_profile["lights"]: color_tuple = get_color_tuple((device_profile["lights"][light])) device.fx.advanced.matrix[ lightmap[light][0], lightmap[light][1] ] = color_tuple except KeyError: error( "light '{}' is not available in lightmap '{}' for device '{}'".format( light, device_profile["lightmap"], device_profile["name"] ) ) exit(1) except Exception as e: error( "failed to set light '{}' for device '{}': {}".format( light, device_profile["name"], e ) ) exit(1) # Apply light colors device.fx.advanced.draw() def iterate_lights(): global device_manager # Turn all lights off for device in device_manager.devices: device.fx.none() device.fx.advanced.draw() # Iterate through all devices for device in device_manager.devices: # Wait five seconds for i in range(5, 0, -1): print("{} will be iterated in {} seconds".format(device.name, i)) time.sleep(1) try: # Turn on one light every second for i in range(device.fx.advanced.rows): for j in range(device.fx.advanced.cols): device.fx.advanced.matrix[i, j] = (255, 255, 255) device.fx.advanced.draw() print("{}: [{}, {}]".format(device.name, i, j)) time.sleep(1) except Exception as e: error("failed to iterate device '{}': {}".format(device.name, e)) exit(1) def list_devices(): print("The following devices are available:") for device in device_manager.devices: print(" - {}".format(device.name)) def list_lightmaps(): global lightmap_directory if len(os.listdir(lightmap_directory)) > 0: print("Available lightmaps:") for lightmap_file in os.listdir(lightmap_directory): print(" - {}".format(lightmap_file[:-5])) else: print("No lightmaps available") def list_profiles(): global profile_directory if len(os.listdir(profile_directory)) > 0: print("Available profiles:") for profile_file in os.listdir(profile_directory): print(" - {}".format(profile_file[:-5])) else: print("No profiles available") if __name__ == "__main__": global device_manager, lightmap_directory, profile_directory # Print logo print_logo() # Parse arguments parser = argparse.ArgumentParser( description="A simple command line frontend for OpenRazer.", formatter_class=RawTextHelpFormatter, ) parser.add_argument( "command", metavar="COMMAND", nargs="?", default=None, help="one of the following:\n list-devices - list available devices\n list-lightmaps - list available lightmaps\n list-profiles - list available profiles\n iterate-lights - iterate though all lights of all devices\n - apply the given profile", ) parser.add_argument( "-ld", "--lightmap-directory", default="{}/.config/rzr/lightmaps".format(Path.home()), help="path to directory with lightmaps (default: ~/.config/rzr/lightmaps)", ) parser.add_argument( "-pd", "--profile-directory", default="{}/.config/rzr/profiles".format(Path.home()), help="path to directory with profiles (default: ~/.config/rzr/profiles)", ) args = parser.parse_args() if not args.command: parser.print_help() exit(0) # Create device manager try: device_manager = DeviceManager() except Exception as e: error("failed to load device manager: {}".format(e)) print("Is the openrazer-daemon running?") exit(1) # Check if directories exist directories_available = True lightmap_directory = args.lightmap_directory profile_directory = args.profile_directory if not os.path.exists(lightmap_directory): error( "lightmap directory '{}' doesn't exist, please create it".format( lightmap_directory ) ) directories_available = False if not os.path.exists(profile_directory): error( "profile directory '{}' doesn't exist, please create it".format( profile_directory ) ) directories_available = False if not directories_available: exit(1) # Execute command if args.command == "list-devices": list_devices() elif args.command == "list-lightmaps": list_lightmaps() elif args.command == "list-profiles": list_profiles() elif args.command == "iterate-lights": iterate_lights() elif args.command: # Load profile try: profile = toml.load("{}/{}.toml".format(profile_directory, args.command)) except FileNotFoundError: error("the profile '{}' doesn't exist".format(args.command)) list_profiles() exit(1) except Exception as e: print(type(e)) error("couldn't load profile '{}': {}".format(args.command, e)) exit(1) for device in profile: apply_lightmap(profile[device]) print("Profile '{}' applied".format(args.command))