ajazz-rgb-cli 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: ajazz-rgb-cli
3
+ Version: 1.0.0
4
+ Summary: A terminal app to configure Ajazz AK820 Pro RGB on Linux
5
+ Requires-Python: >=3.7
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: hidapi>=0.14.0
File without changes
@@ -0,0 +1,150 @@
1
+ import hid
2
+ import time
3
+
4
+ CONTROL_INTERFACE = 3
5
+ PACKET_LENGTH = 64
6
+
7
+ # Command Codes (Preamble packet byte 1)
8
+ CMD_SAVE = 0x02
9
+ CMD_MODE = 0x13
10
+
11
+ MAX_BRIGHTNESS = 5
12
+ MAX_SPEED = 3
13
+ DEFAULT_DIRECTION = 0
14
+
15
+
16
+ LIGHTING_MODES = {
17
+ 'Off': 0x00,
18
+ 'Static': 0x01,
19
+ 'Single On': 0x02,
20
+ 'Single Off': 0x03,
21
+ 'Glittering': 0x04,
22
+ 'Falling': 0x05,
23
+ 'Colourful': 0x06,
24
+ 'Breath': 0x07,
25
+ 'Spectrum': 0x08,
26
+ 'Outward': 0x09,
27
+ 'Scrolling': 0x0a,
28
+ 'Rolling': 0x0b,
29
+ 'Rotating': 0x0c,
30
+ 'Explode': 0x0d,
31
+ 'Launch': 0x0e,
32
+ 'Ripples': 0x0f,
33
+ 'Flowing': 0x10,
34
+ 'Pulsating': 0x11,
35
+ 'Tilt': 0x12,
36
+ 'Shuttle': 0x13,
37
+ }
38
+
39
+ DIRECTIONS = {'Left': 0, 'Down': 1, 'Up': 2, 'Right': 3}
40
+ SLEEP_TIMERS = {'Never': 0, '1 minute': 1, '5 minutes': 2, '30 minutes': 3}
41
+
42
+ class Device:
43
+ def __init__(self, vendor_id, product_id):
44
+ self.vendor_id = vendor_id
45
+ self.product_id = product_id
46
+ self.device = None
47
+
48
+
49
+ def print_device_info(self):
50
+ print("Manufacturer: %s" % self.device.get_manufacturer_string())
51
+ print("Product: %s" % self.device.get_product_string())
52
+ print("Serial No: %s" % self.device.get_serial_number_string())
53
+
54
+ def print_connected_interfaces(self):
55
+ devices = hid.enumerate(self.vendor_id, self.product_id)
56
+ for d in devices:
57
+ print(f"Path: {d['path']}")
58
+ print(f"Interface Number: {d['interface_number']}")
59
+ print(f"Usage Page: {hex(d['usage_page'])} | Usage: {hex(d['usage'])}")
60
+ print("-" * 35)
61
+
62
+
63
+ def connect(self):
64
+ try:
65
+ devices = hid.enumerate(self.vendor_id, self.product_id)
66
+ target_path = None
67
+ for d in devices:
68
+ if d['interface_number'] == CONTROL_INTERFACE:
69
+ target_path = d['path']
70
+ break
71
+ if target_path:
72
+ self.device = hid.device()
73
+ self.device.open_path(target_path)
74
+ # Set non-blocking to 0 so reads wait for the hardware handshake
75
+ self.device.set_nonblocking(0)
76
+ print("Connected to Ajazz AK820 Pro Control Interface!")
77
+ return True
78
+ print("Interface 3 not found.")
79
+ return False
80
+ except Exception as e:
81
+ print(f"Connection failed: {e}")
82
+ return False
83
+
84
+ def _handshake(self):
85
+ try:
86
+ # Read 64 bytes from the feature report stream (with a 500ms timeout)
87
+ response = self.device.get_feature_report(0x00, 65)
88
+ return response
89
+ except Exception:
90
+ # If it times out or skips, clear the buffer safely
91
+ pass
92
+
93
+ def set_static_color(self, r, g, b, mode=LIGHTING_MODES['Static'], rainbow=False, brightness=MAX_BRIGHTNESS, speed=MAX_SPEED, direction=DEFAULT_DIRECTION):
94
+ if not self.device:
95
+ print("Device offline.")
96
+ return
97
+
98
+ try:
99
+ # --- 1. RESET STATE PACKET ---
100
+ reset = [0x00] * 64
101
+ reset[0] = 0x04
102
+ reset[1] = 0x18
103
+ self.device.send_feature_report([0x00] + reset)
104
+ time.sleep(0.02) # Short pause for hardware processing
105
+
106
+ # --- 2. CONFIGURE LIGHTING PACKET ---
107
+ preamble = [0x00] * 64
108
+ preamble[0] = 0x04
109
+ preamble[1] = 0x13
110
+ preamble[8] = 0x01
111
+ self.device.send_feature_report([0x00] + preamble)
112
+
113
+ # --- 3. FIRST HANDSHAKE ---
114
+ self._handshake()
115
+
116
+ # --- 4. LIGHTING DATA PACKET ---
117
+ data = [0x00] * 64
118
+ data[0] = mode
119
+ data[1] = r
120
+ data[2] = g
121
+ data[3] = b
122
+ data[8] = rainbow
123
+ data[9] = brightness
124
+ data[10] = speed
125
+ data[11] = direction
126
+ data[14] = 0x55 # Magic validation footprint
127
+ data[15] = 0xAA # Magic validation footprint
128
+ self.device.send_feature_report([0x00] + data)
129
+ time.sleep(0.02)
130
+
131
+ # --- 5. SAVE PACKET ---
132
+ save = [0x00] * 64
133
+ save[0] = 0x04
134
+ save[1] = 0x02
135
+ self.device.send_feature_report([0x00] + save)
136
+
137
+ # --- 6. SECOND HANDSHAKE ---
138
+ self._handshake()
139
+
140
+ print(f"SetLightingMode sequence executed successfully! RGB({r}, {g}, {b})")
141
+
142
+ except Exception as e:
143
+ print(f"Protocol execution failed: {e}")
144
+
145
+ def close(self):
146
+ try:
147
+ self.device.close()
148
+ except Exception as e:
149
+ print(e)
150
+ print("Could not close device")
@@ -0,0 +1,6 @@
1
+ device_mapper = {
2
+ "Microdia AK820": {
3
+ "VID": 0x0c45,
4
+ "PID": 0x8009
5
+ },
6
+ }
File without changes
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import sys
4
+ import time
5
+
6
+ from .Device_Mapper import device_mapper
7
+ from .Device import Device
8
+ from .utils import hex_to_rgb
9
+
10
+ def main():
11
+ parser = argparse.ArgumentParser(description="Control Ajazz AK820 Pro RGB lighting.",formatter_class=argparse.ArgumentDefaultsHelpFormatter)
12
+
13
+ parser.add_argument(
14
+ '-c', '--color',
15
+ type=hex_to_rgb,
16
+ default=(0, 255, 255),
17
+ help="Hex color code to apply (e.g., FF0000 for Red, 00FFFF for Cyan)"
18
+ )
19
+
20
+ parser.add_argument(
21
+ '-m', '--mode',
22
+ type=int,
23
+ default=1,
24
+ choices=range(0, 20),
25
+ help="Lighting mode ID (0: Off, 1: Static, 2: Single On, 6: Colourful, 7: Breath, 8: Spectrum, 9: Outward, 10: Scrolling, 11: Rolling, 12: Rotating, 13: Explode, 14: Launch, 15: Ripples, 16: Flowing, 17: Pulsating, 18: Tilt, 19: Shuttle)"
26
+ )
27
+
28
+ parser.add_argument(
29
+ '-b', '--brightness',
30
+ type=int,
31
+ default=5,
32
+ choices=range(0, 6),
33
+ help="LED Brightness level scale (0 to 5)"
34
+ )
35
+
36
+ parser.add_argument(
37
+ '-s', '--speed',
38
+ type=int,
39
+ default=3,
40
+ choices=range(0, 6),
41
+ help="Animation effect speed (0 to 5)"
42
+ )
43
+
44
+ parser.add_argument(
45
+ '-d', '--direction',
46
+ type=int,
47
+ default=0,
48
+ choices=range(0, 4),
49
+ help="Animation effect direction (0 to 3)"
50
+ )
51
+
52
+ parser.add_argument(
53
+ '-r', '--rainbow',
54
+ action='store_true',
55
+ help="Enable rainbow effect"
56
+ )
57
+
58
+ parser.add_argument('--vid', type=lambda x: int(x, 16), default=device_mapper["Microdia AK820"]["VID"], help="Vendor ID in Hex")
59
+ parser.add_argument('--pid', type=lambda x: int(x, 16), default=device_mapper["Microdia AK820"]["PID"], help="Product ID in Hex")
60
+
61
+ args = parser.parse_args()
62
+
63
+ r, g, b = args.color
64
+
65
+ dev = Device(args.vid, args.pid)
66
+
67
+ if not dev.connect():
68
+ print("Error: Could not establish communication with the keyboard control endpoint.", file=sys.stderr)
69
+ sys.exit(1)
70
+
71
+ try:
72
+ dev.set_static_color(r, g, b, args.mode, args.rainbow, args.brightness, args.speed, args.direction)
73
+ except Exception as e:
74
+ print(f"Error: {e}", file=sys.stderr)
75
+ sys.exit(1)
76
+ finally:
77
+ dev.close()
78
+
79
+ if __name__ == "__main__":
80
+ main()
@@ -0,0 +1,11 @@
1
+ import argparse
2
+
3
+ def hex_to_rgb(hex_str):
4
+ hex_str = hex_str.lstrip('#').strip()
5
+ if len(hex_str) != 6:
6
+ raise argparse.ArgumentTypeError("Hex color must be exactly 6 hex characters (e.g., FF00FF).")
7
+ try:
8
+ val = int(hex_str, 16)
9
+ return (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff
10
+ except ValueError:
11
+ raise argparse.ArgumentTypeError("Invalid hex characters.")
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: ajazz-rgb-cli
3
+ Version: 1.0.0
4
+ Summary: A terminal app to configure Ajazz AK820 Pro RGB on Linux
5
+ Requires-Python: >=3.7
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: hidapi>=0.14.0
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ ajazz_cli/Device.py
4
+ ajazz_cli/Device_Mapper.py
5
+ ajazz_cli/__init__.py
6
+ ajazz_cli/main.py
7
+ ajazz_cli/utils.py
8
+ ajazz_rgb_cli.egg-info/PKG-INFO
9
+ ajazz_rgb_cli.egg-info/SOURCES.txt
10
+ ajazz_rgb_cli.egg-info/dependency_links.txt
11
+ ajazz_rgb_cli.egg-info/entry_points.txt
12
+ ajazz_rgb_cli.egg-info/requires.txt
13
+ ajazz_rgb_cli.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ajazz_cli = ajazz_cli.main:main
@@ -0,0 +1 @@
1
+ hidapi>=0.14.0
@@ -0,0 +1 @@
1
+ ajazz_cli
@@ -0,0 +1,16 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ajazz-rgb-cli"
7
+ version = "1.0.0"
8
+ description = "A terminal app to configure Ajazz AK820 Pro RGB on Linux"
9
+ readme = "README.md"
10
+ requires-python = ">=3.7"
11
+ dependencies = [
12
+ "hidapi>=0.14.0",
13
+ ]
14
+
15
+ [project.scripts]
16
+ ajazz_cli = "ajazz_cli.main:main"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+