Skip to content

Added support for Arctis Nova 7 gen2#9

Open
tdhowe wants to merge 2 commits intoawth13:mainfrom
tdhowe:tdhowe/nova7
Open

Added support for Arctis Nova 7 gen2#9
tdhowe wants to merge 2 commits intoawth13:mainfrom
tdhowe:tdhowe/nova7

Conversation

@tdhowe
Copy link

@tdhowe tdhowe commented Mar 1, 2026

  • Reworked how it discovers devices a bit so it's a little more scalable if we add support for other devices in the future
  • Added debug logging for chatmix slider

Copy link
Owner

@awth13 awth13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Thank you for your work, this looks great!

I do have a couple minor comments regarding the implementation, please let me know what you think.


def _bind_device(self):
for device_name, device_info in supported_devices.items():
dev = usb.core.find(idVendor=device_info["idVendor"], idProduct=device_info["idProduct"])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of calling find() in a loop, can we do it once and iterate over the result? Looks like usb.core.find() can return an iterator for multiple devices. We could, e.g., match on vendor id, which will always be the same.

import re
import usb.core

supported_devices = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the top-level key into the device record should be the product id? Then we can match against it in _bind_device() when we get an iterator from usb.core.find().

self.die_gracefully(trigger="Couldn't find supported arctis model")
return

self.log.info(f"Found supported device: {device_name} ({hex(device_info['idVendor'])}:{hex(device_info['idProduct'])})")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that device_name gets implicitly bound in the loop above but I think it would be clearer to get it explicitly from a supported_devices record keyed by product id (see my comment on R30).


self.log.info(f"Found supported device: {device_name} ({hex(device_info['idVendor'])}:{hex(device_info['idProduct'])})")
self.dev = dev
inf_idx = device_info["hid_interface_index"]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the different names for the variable here and for the field in supported_devices?

if __name__ == '__main__':
a7pcm_service = Arctis7PlusChatMix()
a7pcm_service.start_modulator_signal()
a7pcm_service.start_modulator_signal() No newline at end of file
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the only change here is that a newline got accidentally removed.

@tdhowe
Copy link
Author

tdhowe commented Mar 2, 2026

@awth13 Sure I will address these later this week. I also realized I didnt update the install stuff - I had to do it manually to get it working (dev.arctis7 was not in my systemd device tree).

Do you want that in a separate PR?

@awth13
Copy link
Owner

awth13 commented Mar 2, 2026

I also realized I didnt update the install stuff - I had to do it manually to get it working (dev.arctis7 was not in my systemd device tree).

Yes, you'll have to add the new device to the installed udev rules. I think it should be in this PR since it is part of adding the new device support. I trust that you will test it as well since I do not have access to the device.

@tdhowe
Copy link
Author

tdhowe commented Mar 2, 2026

I also realized I didnt update the install stuff - I had to do it manually to get it working (dev.arctis7 was not in my systemd device tree).

Yes, you'll have to add the new device to the installed udev rules. I think it should be in this PR since it is part of adding the new device support. I trust that you will test it as well since I do not have access to the device.

Also this part in the .service file:

Requisite=dev-arctis7.device
After=dev-arctis7.device

to

After=pipewire.service pipewire-pulse.service
Requires=pipewire.service

I don't have that device on my pc. I changed mine locally to pipewire instead. Any reason to have the device dependency instead of just pipewire?

@tdhowe
Copy link
Author

tdhowe commented Mar 2, 2026

Ah I see... the rules file names the usb device, is that right? I havent worked much with those before.

@awth13
Copy link
Owner

awth13 commented Mar 2, 2026

the rules file names the usb device, is that right?

Yes, however, once pyusb module binds the device, the device gets detached from the kernel and, consequently, removed from the device tree.

Requisite=dev-arctis7.device
After=dev-arctis7.device

I haven't looked at this code base in a while and, now that you mention it, I don't think these lines are necessary. We only want

[Install]
WantedBy=dev-arctis7.device

This (in combination with the udev rules) tells systemd to start the the service running our script when the device is plugged in. In any case, this is out of scope for this PR -- I will look at it myself when I have time. You can safely remove or ignore Requisite= and After= directives in testing.

- Reworked how it discovers devices a bit so it's a little more scalable if we add support for other devices in the future
- Added opcode filtering on first word so other messages aren't interpreted as chatmix
- Added debug logging for chatmix slider
- Misc cleanup for rules and service registration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants