LCD screen support on NZXT Kraken Zxx devices#479
LCD screen support on NZXT Kraken Zxx devices#479jonasmalacofilho merged 39 commits intoliquidctl:mainfrom
Conversation
jonasmalacofilho
left a comment
There was a problem hiding this comment.
Hi @ShadyNawara,
First, thanks for working on this feature!
images and GiFs are automatically resized and rotated to match the device orientation so there is no need for any preprocessing
That's great!
the kraken z3 device now uses UsbDriver instead of UsbHidDriver. functions for controlling fan and pump speeds were copied over from the krakenx3 driver.
While the bulk interface must obviously be accessed through UsbDriver, and I think it's fine (and maybe even a bit clearer) to have the driver class inherit it, accessing the HID interface through that abstraction has a few problems, the most notable of them being totally incompatible with Mac OS.
So a small architectural change I think is necessary is to have a second "raw device" (e.g. self.hid_device) that's a HidapiDevice (like normally with UsbHidDriver) , and not a PyUsbDevice (which is what self.device is when inheriting UsbDriver).
And then adapt your raw I/O helpers to use them instead of PyUsbDevice read/writes on the interrupt endpoints.
By the way, having PyUSB (LibUSB) claim the bulk interface while the kernel retains the HID interface should be fine, but be aware that there might be a bug with it (I've seem a report somewhere, for LibUSB, but I'm not sure it was totally accurate).
If using the two backends (PyUSB and Hidapi) at the same really doesn't work, then the old "stub" driver will need to be kept, at least for Mac OS.
hwmon was removed
I don't see this, after all, hwmon was not yet implemented for the KrakenZ3: its implementation of get_status() would unconditionally did raw I/O.
Is this what you're referring to, or have I missed something?
I have tested the LCD function which appear to work as expected but I am unable to test the fan control as I plug my fans directly into the motherboard.
That will be important. Do you perhaps have a fan you can use just to test this?
Also, is the pump control working?
I adjusted the automated test for the krakenx3 driver but have not yet created automated test for the z3 driver.
For the time being the old *_not_totally_broken test should be easily adaptable, and it would at least guarantee that the calls don't unexpectedly throw with good input.
I would appreciate any help finishing the remaining checklist items.
Sure, once we go over how things are in this iteration, let me know where you would like me to help.
I also left some comments on the diff.
(There may be a couple of other small things I noticed, but I'll leave them for later as they really aren't critical).
|
Regarding the CI failures:
|
adds a default notsupportedbydevice error for the new set_screen method for all existing drivers. adds pillow as a dependency copied set_color method from the krakenx3 driver renamed krakenx3 driver back to kraken3
|
Thank you for the detailed feedback and the diff comments
I switched to using a second hid device and can confirm the new way works on macos
yes and there were checks in the initialize function for hwmon that applied to both drivers and is now removed
my ram sticks makes the space next to wire ports very tight so I removed the fan and nzxt wires completely. I will check on discord if someone is able to test the fan and color control for the rgb fans. if not, I will try to do it by next weekend update, I tried changing fan speed and the fan duty does seem to change however I am still unable to physically test it yet
pump control is working
sounds good I will add it |
I'm glad to hear that, as I wouldn't be able to test it myself.
Oh, I forgot about those. I see why it makes sense to remove that code, but I think we need to replace it with a warning in case a hwmon kernel driver is found to be bound to the device. if self._hwmon:
_LOGGER.warning("%s is bound to the %s kernel driver,", self.description,
self._hwmon.module)
_LOGGER.warning("and this liquidctl version may interfere with it; to fix the kernel")
_LOGGER.warning("state at any point, unload and reload the %s module",
self._hwmon.module)
_LOGGER.warning("please report this to liquidctl")Otherwise we could significantly mess with its expectations, without alerting the user, or, potentially, even finding out that we need to implement support for that hwmon driver. |
liquidctl/driver/krakenz3.py
Outdated
| hidinfo = next( | ||
| info | ||
| for info in hid.enumerate(device.vendor_id, device.product_id) | ||
| if info["serial_number"] == device.serial_number |
There was a problem hiding this comment.
I have been told that the Kraken Z serial number descriptor is not a true serial number, but just some constant string (probably related to hardware or as-shipped firmware version).
Can you show me what the serial number for your device(s) looks like?
There was a problem hiding this comment.
I had a the black model that I exchanged for the white one and both had different serial numbers. this my current serial number for the white z53: 354F336B3131
the base UsbDriver does not have a self._hwmon, so i am not sure it would be expected. If needed I can replicate what the initializer for UsbHidDriver is doing |
That should work as long as I'll need a couple more days to really review the latest changes. By the way, did you see my hidapi and serial number questions? In the meantime, one conceptually small (but practically large and annoying) architectural change I kinda want to suggest is to use the HID interface as the main device in both drivers. This would make the overall patch much smaller, and, as we tend to prefer HID over direct USB access, it would also keep these drivers more similar to other ones in the repository. I imagine you initially went with |
I think i responded to the serial number question in the other comment but here it is again "I had a the black model that I exchanged for the white one and both had different serial numbers. this my current serial number for the white z53: 354F336B3131"
ok done, tests are now passing as well |
|
an important note is that on windows, this only works when using this branch of libusb: https://github.com/Tpimp/libusb/tree/win-composite-child-support. otherwise I get a |
I couldn't find it even searching for the serial number string. Maybe it go lost or is in a limbo? These past few weeks I've noticed some weird issues with GitHub comments. For instance, I just lost this comment when I was nearly done with it (something which used to be nearly impossible to happen). Anyway... thanks for pasting it again.
That's a relief. You should bring back the check for it in
I think that's only because you have one of these devices. For CI and the rest of us, you'll need to mock a PyUsbDevice and/or monkeypatch the
Given that there's probably still quite a bit for that to be merged (the work on which it's based on is still in review), we'll need to support falling back to a simpler status & cooling only mode. What's the call stack of that exception? Can we detect in a convenient place, and disable the screen functionality then (at runtime)? Also, can we differentiate between the user has not yet replaced the Windows driver with Zadig (I mean, I'm assuming that's necessary on the bulk interface... is this correct?), and they have but aren't running this experimental patch to LibUSB? |
the error only occurs in the _bulk_write method so I think it should be fine as other functions would work as usual
with the experimental libusb patch there is no need to replace any drivers. If liquidctl bundles its own copies of libusb cant it just include the version with the patches? |
I think it should be yes. although, it doesnt really tell us why it failed to switch buckets whether there is a file error, a memory misalignment or something else |
|
Does the response from response = self._write_then_read([0x38, 0x1, mode, bucketIndex])contain more information? If so, you could ask the user to enable Additionally, could dumping (more accurately: logging) |
|
@ShadyNawara Bucket 0 starts with the first byte set to "55" instead of "49". In this case Byte 15 and 16 also do not represent the "bucket index" and "asset index". I modified the _find_next_unoccupied_bucket function to also check for the fist byte being "49": With this I can upload more often (using a bucket starting with 55 leads to the "failed to switch active bucket"-error) however after a while still some memory corruption happens and the error shows up again. I will still be debugging and trying to find maybe more - but implementing a partially reversed engineered protocol is really like poking around in the dark. I pretty confident that the problem is somewhere in that whole bucket memory management code. Thank you so much for developing on this! I really can't wait to have this working :) Edit: I'm running on Manjaro Linux |
I think it was just if it failed or not. Nothing else. For the gif issue though i tested it out yesterday and it was failing on ubuntu but works fine on windows and mac. I need to look into it more on why is that. |
|
Which OS are you mainly using? |
Manjaro Linux (It's an Arch based distribution) |
Thank you, i think there is a possibility that its a linux specific issue, I will investigate. Does it fail after a specific number of gifs or is it random? |
For the same set of gifs as test inputs, the error is deterministic, repeatable and appears after a couple of iterations. The bigger the gif-files are, the earlier the error occurs: BTW: After the error occured the kraken needs a power cycle to respond again to any command. re-initializing or just a reboot (without power cycle) keeps the device unresponsive. |
UPDATE: I am able to replicate the same error on Windows 11 and the behaviour is identical as if I run it on Linux: |
|
If you need any of the output capturing with --debug mode then let me know. |
|
@donbernhardo |
Here are the input gif files (and a script to upload them one after another): Here is the test record when running the included shell script on linux: |
|
@donbernhardo I just pushed an update that should resolve the issue if you can give it a try. I tested it by running your gif set on loop 600 times and it seems to be working fine. fyi, when the device runs out of memory it will briefly switch to liquid mode before loading the gif. The nzxt cam software does a similar thing except they switch to their loading gif instead but I think liquid mode is faster and more reliable. |
|
I'm not hitting any errors on the latest code. Ubuntu 22.04. |
|
@ShadyNawara Thanks a lot for this fix. I hope this branch will make it into a release soon. I have a feeling it will make a lot of people happy espeacially with all the automation one can do way beyond the nzxt cam software! |
|
Love what you're doing here, I just have a question: |
Thats actually what cam does. It creates an image for each frame and pushes it to the device. you might want to check out: Kraken Z Playground i think it does what you are looking for. |
|
After way too long (sorry about that), merged as is. In the next few days I'll probably push some minor complementary docs/readme changes directly to the main branch. One remaining thing that you might want to look into is when there are multiple simultaneous driver instances in use. In part kernel restrictions should already serialize the accesses to the bulk interface, but that might not be sufficient for reliable manipulation of the screen from multiple concurrent instances. |
I took a look, but in the end I just took a screenshot of the dual infographic and wrote a bash script that adds the CPU and liquid temps in two steps with imagemagick. It works 🤷♂️ |
That sounds awesome - can you share it? |
Okay so this is my source image. Then I have a systemd timer: /etc/systemd/system/nzxtupdate.timer /etc/systemd/system/nzxtupdate.service and the script: |
It would be awesome if we could add in the color option to the liquid mode. Even better would be to have the dual cpu/gpu mode with color option. |
Fixes a missing PR checklist item in #479.

Adds support for controlling the LCD screen found on nzxt's Kraken Z series devices
images and GiFs are automatically resized and rotated to match the device orientation so there is no need for any preprocessing
The original Kraken3 driver was renamed to krakenx3and a new driver Krakenz3 was created. kraken z3 uses a dual usb interface consisting of an HID device and regular usb device. the kraken z3 device now uses UsbDriver instead of UsbHidDriver. functions for controlling fan and pump speeds were copied over from the krakenx3 driver.hwmon was removed
I have tested the LCD function which appear to work as expected but I am unable to test the fan control as I plug my fans directly into the motherboard.
I adjusted the automated test for the krakenx3 driver but have not yet created automated test for the z3 driver.
I would appreciate any help finishing the remaining checklist items.
Closes: #444
Checklist:
liquidctl.8Linux/Unix/Mac OS man pagedocs/*guide.mddevice guidesNew CLI flag?
extra/completions/New device?
extra/linux/71-liquidctl.rules(instructions in the file header)en)New driver?
docs/developer/protocol/