A script to change settings of the Wired Gaming Mouse T1 when running Linux.
Last active
June 2, 2020 22:36
-
-
Save pklaus/56ee78d26593d33d906c to your computer and use it in GitHub Desktop.
Easterntimes Tech Wired Gaming Mouse T1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Script to control the | |
Easterntimes Tech | |
Wired Gaming Mouse T1 | |
via PyUSB. | |
""" | |
import sys, argparse, textwrap, logging | |
import usb.core, usb.util | |
logger = logging.getLogger(name=__name__) | |
class WiredGamingMouseT1(object): | |
idVendor = 0x04d9 | |
idProduct = 0xfc07 | |
brightness_map = {'bright': 3, 'medium': 2, 'dim': 1, 'off': 0} | |
breathing_map = {'fast': 1, 'medium': 3, 'slow': 6, 'off': 0} | |
def __init__(self): | |
# Device Initialization | |
dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct) | |
try: | |
if dev.is_kernel_driver_active(2): | |
dev.detach_kernel_driver(2) | |
except usb.core.USBError as e: | |
msg = """ | |
Could not interact with the device. This tool needs to be run as root | |
or you need to set the right permissions on the usb device: | |
sudo chmod 666 /dev/bus/usb/{bus:03d}/{address:03d} | |
Or you can let udev configure the permissions automatically by putting this rule: | |
SUBSYSTEM=="usb", ATTR{{idVendor}}=="04d9", ATTR{{idProduct}}=="fc07", MODE="0666", SYMLINK+="wgmt1" | |
into the file /etc/udev/rules.d/99-wgmt1.rules. | |
""" | |
sys.exit(textwrap.dedent(msg.format(bus=dev.bus, address=dev.address))) | |
usb.util.claim_interface(dev, 2) | |
self.dev = dev | |
def send_ctrl_msg(self, data, big=False): | |
logger.debug('sending: ' + repr(data)) | |
val = 0x0303 if big else 0x0302 | |
self.dev.ctrl_transfer(0x21, 9, val, 2, data) | |
def set_color(self, rgb, brightness='bright', breathing='off'): | |
""" send a URB message via PyUSB and change the LED color """ | |
r, g, b = (255 - col for col in rgb) | |
brightness, breathing = self.sanitize_brightness_breathing(brightness, breathing) | |
msg = bytes([0x2, 0x4, r, g, b, brightness, breathing, 0, 0, 0, 0, 0, 0, 0, 0, 0]) | |
self.send_ctrl_msg(msg) | |
def set_profile(self, profile): | |
""" send a URB message via PyUSB and change the profile """ | |
assert profile in range(0, 5) | |
msg = bytes([2,2,0x43,0,1,0,0xfa,0xfa,profile,0,0,0,0,0,0,0]) | |
self.send_ctrl_msg(msg) | |
msg = bytes([2,1,1,profile,0,0,0,0,0,0,0,0,0,0,0,0]) | |
self.send_ctrl_msg(msg) | |
def set_cpi(self, profile, cpi_steps): | |
""" | |
cpi_steps must be an iterable of length 5 | |
each consisting of a number going from 0 to 16 | |
""" | |
assert len(cpi_steps) == 5 | |
msg = [3,2,0x4f,2,0x2a,0,0xfa,0xfa,5,profile] | |
for cpi_step in cpi_steps: | |
if cpi_step in range(0, 17): | |
enable = 1 | |
else: | |
enable = 0 | |
cpi_step = 0 | |
msg += [enable,cpi_step,0,cpi_step,0,0,0,0] | |
msg += [0] * 14 | |
msg = bytes(msg) | |
self.send_ctrl_msg(msg, big=True) | |
logger.info('You need to switch to the profile now to enable the new settings.') | |
def sanitize_brightness_breathing(self, brightness, breathing): | |
if type(brightness) == str: | |
brightness = self.brightness_map[brightness] | |
if type(breathing) == str: | |
breathing = self.breathing_map[breathing] | |
assert brightness in (0,1,2,3) | |
assert breathing in (0,1,3,6) | |
return brightness, breathing | |
def set_brightness_breathing(self, profile, brightness, breathing): | |
""" """ | |
brightness, breathing = self.sanitize_brightness_breathing(brightness, breathing) | |
msg = bytes([2,2,0xf1,profile,6,0,0xfa,0xfa,0xf1,0xf0,0,brightness,breathing,0,0,0]) | |
logger.debug('Sending this now: ' + repr(msg)) | |
self.send_ctrl_msg(msg) | |
logger.info('You need to switch to the profile now to enable the new settings.') | |
def cpi_steps(string): | |
""" | |
argparse type definition to enter CPI steps. | |
""" | |
try: | |
steps = [int(part) for part in string.split(',')] | |
assert len(steps) == 5 | |
return steps | |
except: | |
raise argparse.ArgumentTypeError('Not a proper CPI steps value.') | |
def hex_rgb(string): | |
""" | |
argparse type definition to enter RGB | |
values as a 3- or 6- digit hex number | |
""" | |
try: | |
if len(string) == 3: | |
string = string[0] * 2 + string[1] * 2 + string[2] * 2 | |
assert len(string) == 6 | |
r, g, b = string[0:2], string[2:4], string[4:6] | |
return (int(col, 16) for col in (r, g, b)) | |
except: | |
raise argparse.ArgumentTypeError('Not a proper RGB hex value.') | |
def main(): | |
parser = argparse.ArgumentParser(description=__doc__) | |
parser.add_argument('--debug', action='store_true') | |
profile_parser = argparse.ArgumentParser(add_help=False) | |
profile_parser.add_argument('profile', type=int, choices=range(0,5), help='Profile') | |
subparsers = parser.add_subparsers(dest='action', metavar='<action>', help="Action to perform:") | |
# set-color | |
action_desc = 'Set the LED color of the mouse' | |
set_color_parser = subparsers.add_parser('col', | |
description=action_desc, help=action_desc) | |
set_color_parser.add_argument('color', type=hex_rgb, metavar='RRGGBB', help='New LED color') | |
set_color_parser.add_argument('--brightness', choices=WiredGamingMouseT1.brightness_map.keys(), default='bright', help='Brightness') | |
set_color_parser.add_argument('--breathing', choices=WiredGamingMouseT1.breathing_map.keys(), default='off', help='Breathing') | |
# switch-profile | |
action_desc = 'Switch to a different mouse profile' | |
switch_profile_parser = subparsers.add_parser('sp', | |
description=action_desc, parents=[profile_parser], help=action_desc) | |
# cpi-steps | |
action_desc = 'Set the CPI (counts-per-inch) steps' | |
switch_profile_parser = subparsers.add_parser('cs', | |
description=action_desc, parents=[profile_parser], help=action_desc) | |
switch_profile_parser.add_argument('steps', type=cpi_steps, | |
help='Comma separated list of CPI steps for the specified profile. Default: 2,3,6,13,16. Use -1 to disable a step.') | |
# brightness-breathing | |
action_desc = 'Change the brightness & breathing settings' | |
brightness_breathing_parser = subparsers.add_parser('bb', | |
description=action_desc, parents=[profile_parser], help=action_desc) | |
brightness_breathing_parser.add_argument('brightness', choices=WiredGamingMouseT1.brightness_map.keys(), help='Brightness') | |
brightness_breathing_parser.add_argument('breathing', choices=WiredGamingMouseT1.breathing_map.keys(), help='Breathing') | |
args = parser.parse_args() | |
if not args.action: parser.error("Please choose and action.") | |
level = logging.DEBUG if args.debug else logging.INFO | |
logging.basicConfig(format='%(levelname)s: %(message)s', level=level) | |
t1 = WiredGamingMouseT1() | |
if args.action == 'col': t1.set_color(args.color, args.brightness, args.breathing) | |
if args.action == 'sp': t1.set_profile(args.profile) | |
if args.action == 'cs': t1.set_cpi(args.profile, args.steps) | |
if args.action == 'bb': t1.set_brightness_breathing(args.profile, args.brightness, args.breathing) | |
if __name__ == "__main__": main() | |
Probably your usb vendorID or productID are different, check them out using lsusb or dmesg and update the py script.
I'm trying to run this stuff on a T3 version of the same mouse, but no luck, I'm missing the usb HID "device".... meh
I'll check in spare time...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I'm getting the following error when I try to run it
Command:
Error:
I am running Ubuntu 15.10 with both PyUSB and libusb-1.0-0 installed, do you know what I have done wrong?