subraizada3 / 27gn950controller

Control bias lighting on the LG 27GN950 monitor
Other
63 stars 12 forks source link

Windows support/Multiple Displays #2

Closed koshisan closed 3 years ago

koshisan commented 3 years ago

Hi!

Thanks for (potentially) saving us all from having to rely in LG's software department!

I am trying to run control.py on Windows. However, I do get an error message:

raceback (most recent call last): File "control.py", line 35, in <module> dev = usb.core.find(idVendor=0x043e, idProduct = 0x9a8a) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 1299, in find raise NoBackendError('No backend available') usb.core.NoBackendError: No backend available

Which is not correct - In fact there are even two backends available, since I am running two LG27GN950 ;)

I am not really sure if the script is supposed to be running on Windows at all - but if it did and if it were to support multiple monitors, it could do more than LGs software, which is refusing any kind of control at all when running in a multiple monitor setup...

dmitrii-galantsev commented 3 years ago

I believe he hasn't tested with windows.

subraizada3 commented 3 years ago

That error is for PyUSB not being able to find an interface to communicate with the OS's (Windows's) USB subsystem.

I booted into my Windows installation and these steps were sufficient to make it work:

Now the libusb backend needs to be installed.

I did make a minor code update to control.py to make it Windows compatible so you'll need to update the copy you have.

I don't own two of these monitors, would be interested in seeing how it works for you.

koshisan commented 3 years ago

Wow! Thank you very much - I indeed didn't realize that pyusb had further dependencies not installed by pip. I did install libusb and updated the the code.

I can confirm that it now does work on windows! However, it does only work on one monitor.

Unfortunately I never did anything in python the script would probably either need to provide a selection which "dev" object should be used or apply everything to all "dev" objects found.

In my opinion that should depend on if you plan to implement options to sync the screen/set colors in the future.

Especially video sync only really makes sense on one display.

(Did you ever figure out how to realize that? I checked if it would be able to grab the screen content at all at from python at a fast enough pace, but the trick seems to be to just take a screenshot and scale it down: https://github.com/digital-concrete/light-sync)

On the other hand selectable displays would add more complexity to running the script non-interactively (which I would really love to see - because that would make it possible to integrate the lights into my smarthome setup), since at least two arguments would have to be parsed...

Like I said I am not really familiar with python, but if I can help debugging, etc. I am all in for it!

subraizada3 commented 3 years ago

I added multimonitor support. Obviously I can't test it, but it should work. See the readme for information. I also added a noninteractive mode.

For video sync, see issue #1. I don't know how the protocol encodes the color information, and it seems nontrivial to figure that out.

koshisan commented 3 years ago

Thanks again for your work! Unfortunately that seems to have broken something:

File "control.py", line 52, in dev.set_configuration() File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 905, in set_configuration self._ctx.managed_set_configuration(self, configuration) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, *args, *kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 158, in managed_set_configuration self.managed_open() File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, args, **kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 131, in managed_open self.handle = self.backend.open_device(self.dev) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 804, in open_device return _DeviceHandle(dev) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 652, in init _check(_lib.libusb_open(self.devid, byref(self.handle))) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 604, in _check raise USBError(_strerror(ret), ret, _libusb_errno[ret]) usb.core.USBError: [Errno 5] Input/Output Error

If I comment out the part causing the error it says that two monitors are detected - so that part seems to work

subraizada3 commented 3 years ago

Does everything else (e.g. actually controlling the lighting) work properly with line 52 commented out?

koshisan commented 3 years ago

No, it gives the same error on "cfg = dev.get_active_configuration() # TODO: is this necessary? cfg is unused."

It only starts when I completely disable lines 51-53 - but that doesn't get me very far:

C:\AutoHotkey>python control.py Found 2 monitors TurnOn invalid command TurnOff invalid command h Traceback (most recent call last): File "control.py", line 245, in launchCli() File "control.py", line 174, in launchCli cliProcess(text) File "control.py", line 139, in cliProcess print(helpstring) NameError: name 'helpstring' is not defined

Edit: It's turnOn, not TurnOn - However, that results in:

Found 2 monitors turnOn Traceback (most recent call last): File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 236, in get_interface_and_endpoint return self._ep_info[endpoint_address] KeyError: 2

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "control.py", line 245, in launchCli() File "control.py", line 174, in launchCli cliProcess(text) File "control.py", line 145, in cliProcess sendControlCode(cmd, devnum) File "control.py", line 93, in sendControlCode sendStr(part1 + part2_1 + part3, devnum) File "control.py", line 57, in sendStr sendInt(int(data, 16), devnum) File "control.py", line 69, in sendInt dev.write(2, data.to_bytes(64, byteorder='big')) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 976, in write intf, ep = self._ctx.setup_request(self, endpoint) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, *args, kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 228, in setup_request intf, ep = self.get_interface_and_endpoint(device, endpoint_address) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, *args, *kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 238, in get_interface_and_endpoint for intf in self.get_active_configuration(device): File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, args, kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 249, in get_active_configuration self.managed_open() File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, *args, **kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 131, in managed_open self.handle = self.backend.open_device(self.dev) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 804, in open_device return _DeviceHandle(dev) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 652, in init _check(_lib.libusb_open(self.devid, byref(self.handle))) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 604, in _check raise USBError(_strerror(ret), ret, _libusb_errno[ret]) usb.core.USBError: [Errno 5] Input/Output Error

subraizada3 commented 3 years ago

I've pushed an update which prints some debug info. If you could paste the output from that into something like pastebin.com and share the URL, that would be helpful.

koshisan commented 3 years ago

Of course! https://pastebin.com/j6B8TGJj

subraizada3 commented 3 years ago

It seems that libusb is unable to read the properties of or communicate with the second monitor. For example, the information printed for the first monitor has:

 iManufacturer          :    0x1 LG Electronics Inc.
 iProduct               :    0x3 LG UltraGear Monitor
 iSerialNumber          :    0x4 104NTJJJD828

And for the second monitor it has:

 iManufacturer          :    0x1 Error Accessing String
 iProduct               :    0x3 Error Accessing String
 iSerialNumber          :    0x4 Error Accessing String

At this point there are two things that I have left to suggest. 1:

image

image

Then you can run control.py again and hopefully it'll work. If not, you can double click the device in Device Manager, go to the Driver tab and Roll Back the drivers, which will undo the modifications from Zadig and allow the LG control center to work again.

Or, the very final thing I can suggest, is that you could also try using the libusb-win32 backend instead of the libusb1 backend which you currently have. Roll back the drivers, then from C:\Windows\System32, delete the libusb-1.0.dll to uninstall the libusb1 backend. From https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/ download libusb-win32-devel-filter-1.2.6.0.exe, run it to install LibUSB, then run the filter wizard and install the device filter for the LG UltraGear monitor device. Try control.py again; if it still doesn't work then you can run the filter wizard again to remove the libusb device filters and then rollback the drivers from Device Manager.

For me with one monitor it works in all three configurations (the existing libusb1 backend, the Zadig WinUSB drivers, and with the libusb-win32 backend). But unfortunately I don't really know why this is happening, and if none of that fixes it then I don't know where to go from there. Good luck!

koshisan commented 3 years ago

Big thanks! Replacing the drivers did work!

I am now able to use every function currently implemented!

Btw: LG control is also still working - I suspect that most functions work over DDC instead of USB. I spend a few hours the other day trying to trick the Ultragear software into recognizing only one display with DDC manipulation - until I realized it just refuses to work in any multi display configuration - regardless if both of them are LG... So my best guess right now is that only Ultragear requires USB for the light setup.

Btw: Did you see my reply to #1? I bet it's just a prefix and a color code for every individual LED...

subraizada3 commented 3 years ago

Awesome! So you can control both or individual monitors? And did you have to use the Zadig/WinUSB drivers or the libusb-win32 drivers? I can update the documentation with that information.

koshisan commented 3 years ago

Yes - I can control them both or individually - everything works as intented. I am using the WinUSB driver (default setting of Zadig)

subraizada3 commented 3 years ago

Thanks. I wrote up a Windows setup guide (here) and linked it from the readme. Hopefully that'll help other people in the future. It's kind of sad that (aside from video sync) this is already ahead of what LG's official lighting software does.

I also deleted a line from control.py that I believe is completely unnecessary, and has no effect on the functionality or operation of the program. But it was related to the part of the code causing some of the issues you were having, so let me know if the latest version causes any issues and I'll add it back in.

Aside from that, this issue seems to be fully resolved. Feel free to give a ping back here if you release any software/code for this monitor for your smart home control project.

koshisan commented 3 years ago

Still working :) One interesting find though: Running LG OnScreen Control seems to block access to the USB devices - but only sometimes. It was working fine earlier, after returning to the office (and powercycling the monitors inbetween) I got:

C:\AutoHotkey>python control.py turnOn Traceback (most recent call last): File "control.py", line 66, in dev.set_configuration() File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 905, in set_configuration self._ctx.managed_set_configuration(self, configuration) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, *args, *kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 158, in managed_set_configuration self.managed_open() File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 113, in wrapper return f(self, args, **kwargs) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 131, in managed_open self.handle = self.backend.open_device(self.dev) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 804, in open_device return _DeviceHandle(dev) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 652, in init _check(_lib.libusb_open(self.devid, byref(self.handle))) File "C:\Users\koshi\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 604, in _check raise USBError(_strerror(ret), ret, _libusb_errno[ret]) usb.core.USBError: [Errno 5] Input/Output Error

After closing the LG software everything runs fine again - just in case anyone is asking!

Thank you for your help today! There will probably no code released for my smarthome project, since it is not "real" software development work but more hacking everything together with IOTLink (software for windows remote control), MQTT, Node-red and OpenHab. Once setting the colors/synchronization works, I can use it to integrate the monitors into my normal light scenes...