Replies: 3 comments 2 replies
-
Yeah using those events would be good to do. I havent done anything as I wasnt aware they existed. I think I would prefer an api like export type MonitorCallback = (e: 'add' | 'remove', info: SomeDataHere) => void
export type UnsubCallback = () => void
export function monitorStreamdecks(cb: MonitorCallback): UnsubCallback To make it easier to track subscribers. For node, it is possible to monitor with https://github.com/MadLittleMods/node-usb-detection, but that library is prone to the occasional segfault. I am working on fixing that, as I too want to be able to monitor for streamdecks but havent finished that work yet |
Beta Was this translation helpful? Give feedback.
-
Here's a polling system that I wrote. Not fully tested yet. Feel free to use/modify/ignore. /**
* Polling for Stream Deck (dis)connections
*/
import EventEmitter from 'events'
import { listStreamDecks } from '@elgato-stream-deck/node'
// StreamDeckDeviceInfo should probably be exported directly from '@elgato-stream-deck/node', but...
import { StreamDeckDeviceInfo } from '@elgato-stream-deck/node/dist/device'
let streamDeckInfoList = [] as StreamDeckDeviceInfo[]
class StreamDeckMonitor extends EventEmitter {
static singleton: StreamDeckMonitor = new StreamDeckMonitor()
static getSingleton(): StreamDeckMonitor {
return StreamDeckMonitor.singleton
}
}
/**
* streamDeckMonitor.on('added', (added: StreamdeckDeviceInfo[]) => { do something })
* streamDeckMonitor.on('removed', (removed: StreamdeckDeviceInfo[]) => { do something })
*/
export const streamDeckMonitor = StreamDeckMonitor.getSingleton()
const poll = () => {
const newStreamDeckInfoList = listStreamDecks()
const added = newStreamDeckInfoList.filter(
(newInfo) =>
!streamDeckInfoList.some((oldInfo) => newInfo.path === oldInfo.path)
)
const removed = streamDeckInfoList.filter(
(oldInfo) =>
!newStreamDeckInfoList.some((newInfo) => newInfo.path === oldInfo.path)
)
streamDeckInfoList = newStreamDeckInfoList
if (added.length) {
streamDeckMonitor.emit('added', added)
}
if (removed.length) {
streamDeckMonitor.emit('removed', removed)
}
}
setInterval(poll.bind(this), 5000)
// if we call poll() immediately,
// it may emit before any listeners have connected
// so we queue it as a microtask
Promise.resolve().then(poll.bind(this)) |
Beta Was this translation helpful? Give feedback.
-
Okay! Here's a new version which uses node-usb-detection. I'm debouncing the function which calls Apologies for the Electron references in here, but they'll be helpful for anyone solving this problem in Electron. /**
* Monitoring for Stream Deck (dis)connections
*/
import { app } from 'electron'
import EventEmitter from 'events'
import { debounce } from 'lodash'
import usbDetect from 'usb-detection'
import { listStreamDecks } from '@elgato-stream-deck/node'
import { VENDOR_ID, DEVICE_MODELS } from '@elgato-stream-deck/core'
// StreamDeckDeviceInfo should probably be exported directly from '@elgato-stream-deck/node', but...
import { StreamDeckDeviceInfo } from '@elgato-stream-deck/node/dist/device'
let streamDeckInfoList = [] as StreamDeckDeviceInfo[]
usbDetect.startMonitoring()
app.on('before-quit', () => {
usbDetect.stopMonitoring()
})
class StreamDeckMonitor extends EventEmitter {
static singleton: StreamDeckMonitor = new StreamDeckMonitor()
static getSingleton(): StreamDeckMonitor {
return StreamDeckMonitor.singleton
}
}
/**
* streamDeckMonitor.on('added', (added: StreamdeckDeviceInfo[]) => { do something })
* streamDeckMonitor.on('removed', (removed: StreamdeckDeviceInfo[]) => { do something })
*/
export const streamDeckMonitor = StreamDeckMonitor.getSingleton()
usbDetect.on(`add:${VENDOR_ID}`, elgatoDeviceChanged)
usbDetect.on(`remove:${VENDOR_ID}`, elgatoDeviceChanged)
function elgatoDeviceChanged(device: usbDetect.Device) {
const isStreamDeck = DEVICE_MODELS.some((model) => {
return device.productId === model.productId
})
if (isStreamDeck) {
debouncedRefreshStreamDecks()
}
}
/**
* Debounce the refreshStreamDecks function.
* This will also delay execution
* so that refreshStreamDecks() will return
* correct information. (feels like a hack)
*/
const debouncedRefreshStreamDecks = debounce(refreshStreamDecks, 2000)
function refreshStreamDecks(): void {
const newStreamDeckInfoList = listStreamDecks()
const added = newStreamDeckInfoList.filter(
(newInfo) =>
!streamDeckInfoList.some((oldInfo) => newInfo.path === oldInfo.path)
)
const removed = streamDeckInfoList.filter(
(oldInfo) =>
!newStreamDeckInfoList.some((newInfo) => newInfo.path === oldInfo.path)
)
streamDeckInfoList = newStreamDeckInfoList
if (added.length) {
streamDeckMonitor.emit('added', added)
}
if (removed.length) {
streamDeckMonitor.emit('removed', removed)
}
}
app.whenReady().then(() => {
Promise.resolve().then(debouncedRefreshStreamDecks)
}) |
Beta Was this translation helpful? Give feedback.
-
In the WebHID version, (I'm guessing) we could monitor
navigator.hid.onconnect
andnavigator.hid.ondisconnect
to check for Stream Decks being connected or disconnected. Is there a similar option for the NodeJS version? Or do we need to set up asetInterval()
timer and start polling?If possible, it would be to have this type of functionality in both versions. Something like:
Beta Was this translation helpful? Give feedback.
All reactions