foxxyz/loupedeck

WebSerial support

Xample opened this issue · 17 comments

Hello, while it might not be as useful as in a node demon, how difficult would you think a port to Web USB would be ?

Probably makes more sense to look at Web Serial

I did not know about Web Serial, I'm now wondering if Web USB is a subclass of Web Serial of it's own.

those docs dont apply as this library isnt using that usb package. It is using https://www.npmjs.com/package/serialport

I just made a POC using WebUSB, while I can request the device using the vendorId, the device exposes 5 interfaces. Only 1 can be claimed, the others raise an exception
SecurityError: Failed to execute 'claimInterface' on 'USBDevice': The requested interface implements a protected class.
The loupedeck is probably seen as either a video or an HID (or even both but through 2 interfaces).

In short… WebUSB is not the good way to go.

[EDIT] This is not HID as it would otherwise be listed using the WebHID. Also the interface 2 is the flash drive
[EDIT 2] I was wrong!, I just used wireshark to see the USB traffic, the device 1 and endpoint 1 are used, and those are the one we can connect to using WebUSB. I need to check why I was not able to read anything.

Should be totally possible. I would personally try using WebSerial instead of WebUSB, and add a little webpage/GUI component to it as an example and for testing. Could be fun.

For using WebSerial I'm wondering if I will get the same limitation with Chrome i.e. if you can do it with WebUSB it will then force you to use WebUSB. (The same applies with WebHID where you cannot use WebUSB)

Also, to what I've seen, the ws.js is using a websocket to connect to the discovered serialport (which one is exposed through a host address). I have not tested but Chome might prevent connecting (through a WS) to this local address, if at least I had an address because to what I've seen:
https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API directly returns a port where we can pipe data, not a host we can connect to.

For now, using WebUSB, I've been able to send the handshake and received the response (using your WS_UPGRADE_HEADER data) but I don't know how to then read the upcoming incoming data. I can imagine I could in a perfect world have the abstraction WebUSB-> USBInterface -> Websocket -> LoupedeckRPC -> LoupedeckAPI -> Nice website. But the browser's WebSocket cannot connect to the USBInterface so I feel like I will have to fake it.

[UPDATE] It works now… i.e. I can receive data from the loupedeck, I think I had to reset the device.

Older firmwares created a virtual network interface, and you had to open a websocket connection to them.
Newer firmwares appear as a serialport.

I also expect that chrome will block access to the websocket version, so that route is probably a deadend.
For the newer serial devices, using WebSerial would make sense. What I expect you have done is find the serialport through WebUSB, and are having to implement a serialport driver.

Little POC working: https://angular-ivy-pcm6gq.stackblitz.io/

But I've to click twice on the start button to make it work properly (I need to check why, I probably need to reset the usb interface or something like that), the data is sent to the console (when we move the knobs of course).

[EDIT] no need to send the handshake, this probably drops the support for older firmware, but conversely it's working properly now. Thank you @Julusian

Hi, here is a new working and more stable version using WebUSB
https://github-e23slq.stackblitz.io/

Requirements:

  • A connected loupedeck
  • No other loupedeck manager, not even a second window of the link above (no other app should have claimed the interface number 1)
  • Using chrome, click the "discover" button to see the list of devices, you should see your loupedeck
  • Once added, just touch any button / turn knobs or tactile screen. By default, the app will print the result of the first device.
  • Tested on a loupedeck CT (where the product Id is 0003 by the way)

That's it for now

Also: The trouble I had yesterday is that the device could stay in a dangling state if you handshake in the middle of a session (in which case the response will timeout and I call a reset on the usb) or if I'm reading using the transferIn but the promise is stuck because the device did not answer to it (no outcomming event to fire). In that case, either the device is stuck in a lock or chrome kept the unresolved promise after a refresh.

Feel feel to delete this comment, as it is promoting an alternate loupedeck library.

I had a play around with this yesterday in my own library, and got something working. Its using WebSerial and is not very refined yet (has quirks like re-pairing the same device fails because its already open, can probably get stuck easily. code definitely needs some tidying).

The main code of interest is https://github.com/Julusian/node-loupedeck/blob/main/packages/web/src/serial.ts, which you are welcome to use as a reference for an implementation here. It will need some work, but will serve as a good reference to do a browser based implementation of https://github.com/foxxyz/loupedeck/blob/master/connections/serial.js
With a crude demo at https://julusian.github.io/node-loupedeck/

Nice! however, my Loupedeck CT is not found, is this because you do only expose the LoupedeckLive and LoupedeckLiveS ?
image
(Chrome MacOS)

Yeah, it only allows known models, and the CT is not one of those unfortunately

I've published support for WebSerial in the 4.1.0-beta.0 release awaiting merge in #23, including a new example that can be used to test.

Please test it and let me know if you have success using it (or not!).

@Xample any chance you have an extra CT that you be willing to lend to me for a week so I could add support for it? I can pay for shipping!

@foxxyz I'm using it every day, but it would be helpful for everyone. The differences : There are 2 displays on the CT, one on the knob and the second one on the buttons. Also, the knob in the middle is a touchpad and will emit the related events. All the events coming from the CT are easy to record, the only hard part (that I did not yet) is to detect how the buffer is sent to the round touch button. Are you in LA ?

@Xample Yes I am. And you in Switzerland, correct? I tried to find a way to privately contact you, but wasn't able to.

My email is in every commit on this repository if you want to shoot me an email so we can work out the details.

Thanks and let me know!