1
0
Fork 0
mirror of https://github.com/moritzruth/node-enttec-open-dmx-usb.git synced 2025-04-20 15:21:21 +02:00

Allow providing a usleep-compatible function to account for setTimeout inaccuracies

Also: Update dependencies
This commit is contained in:
Moritz Ruth 2023-05-16 15:42:14 +02:00
parent e1a78c6044
commit e16af171a7
Signed by: moritzruth
GPG key ID: C9BBAB79405EE56D
7 changed files with 685 additions and 2360 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
node_modules/
dist/
.idea/
/test.mjs

2
.nvmrc
View file

@ -1 +1 @@
10
18

View file

@ -1,6 +1,6 @@
# node-enttec-open-dmx-usb 🔌
> A Node.js library for interacting with the
> [Enttec Open DMX USB Interface](https://www.enttec.co.uk/en/product/controls/dmx-usb-interfaces/open-dmx-usb/)
> [Enttec Open DMX USB interface](https://www.enttec.co.uk/en/product/controls/dmx-usb-interfaces/open-dmx-usb/)
As it uses `serialport` under the hood, it should also work in
[these environments](https://serialport.io/docs/guide-platform-support#supported-platforms-and-architectures).
@ -8,7 +8,7 @@ As it uses `serialport` under the hood, it should also work in
## Install
![npm](https://img.shields.io/npm/v/enttec-open-dmx-usb?style=flat-square)
Minimum required Node.js version is `v14.0.0`.
The minimum required Node.js version is `v18.0.0`.
```sh
yarn add enttec-open-dmx-usb
@ -20,7 +20,7 @@ npm install enttec-open-dmx-usb
[**View documentation on jsdocs.io**](https://www.jsdocs.io/package/enttec-open-dmx-usb#EnttecOpenDMXUSBDevice)
```js
import { EnttecOpenDMXUSBDevice as DMXDevice } from "enttec-open-dmx-usb";
import { EnttecOpenDMXUSBDevice as DMXDevice } from "enttec-open-dmx-usb"
(async () => {
const device = new DMXDevice(await DMXDevice.getFirstAvailableDevice())
@ -38,7 +38,31 @@ import { EnttecOpenDMXUSBDevice as DMXDevice } from "enttec-open-dmx-usb";
})()
```
### What to do when this doesnt work
TLDR: Because `setTimeout` is imprecise, install [`easy-sleep`](https://github.com/qufei1993/easy-sleep) and
pass the `usleep` function provided by it as the third parameter to the constructor of `EnttecOpenDMXUSBDevice`.
See the example below.
From [the Node.js documentation](https://nodejs.org/api/timers.html#settimeoutcallback-delay-args) regarding `setTimeout`:
> Node.js makes no guarantees about the exact timing of when callbacks will fire, nor of their ordering.
> The callback will be called as close as possible to the time specified.
Because of this and the passive nature of the Enttec Open DMX USB interface, sometimes the timing requirements of the DMX specification are not met.
Using a library such as [`easy-sleep`](https://github.com/qufei1993/easy-sleep) which allows sleeping (i. e. blocking the event loop) for a precise
amount of microseconds is a possible workaround.
You may pass a function sleeping for `n` *micro*seconds as the third parameter to the constructor of `EnttecOpenDMXUSBDevice`.
For example, using `easy-sleep`:
```js
import { EnttecOpenDMXUSBDevice as DMXDevice } from "enttec-open-dmx-usb"
import easySleep from "easy-sleep"
new DMXDevice(await DMXDevice.getFirstAvailableDevice(), true, easySleep.Thread.usleep)
```
## Events
`ready` - `startSending` can be called.
`ready` - `startSending` may be called.
`error` - An error occurred. `error` events from `serialport` are passed through.

View file

@ -13,25 +13,21 @@
"usb"
],
"scripts": {
"build": "tsc",
"lint": "eslint src"
"build": "tsc"
},
"files": [
"dist"
],
"engines": {
"node": ">=14.0.0"
"node": ">=18.0.0"
},
"devDependencies": {
"@types/node": "^14.14.31",
"@types/serialport": "^8.0.1",
"eslint": "^7.20.0",
"eslint-config-awzzm-node": "^1.5.0",
"eslint-config-awzzm-ts": "^1.5.2",
"typescript": "~4.1.5"
"@types/node": "^18.16.10",
"@types/serialport": "^8.0.2",
"typescript": "^5.0.4"
},
"dependencies": {
"eventemitter3": "^4.0.7",
"serialport": "^9.0.7"
"eventemitter3": "^5.0.1",
"serialport": "^11.0.0"
}
}

613
pnpm-lock.yaml generated Normal file
View file

@ -0,0 +1,613 @@
lockfileVersion: '6.0'
dependencies:
easy-sleep:
specifier: ^1.2.2
version: 1.2.2
eventemitter3:
specifier: ^5.0.1
version: 5.0.1
serialport:
specifier: ^11.0.0
version: 11.0.0
devDependencies:
'@types/node':
specifier: ^18.16.10
version: 18.16.10
'@types/serialport':
specifier: ^8.0.2
version: 8.0.2
typescript:
specifier: ^5.0.4
version: 5.0.4
packages:
/@serialport/binding-mock@10.2.2:
resolution: {integrity: sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw==}
engines: {node: '>=12.0.0'}
dependencies:
'@serialport/bindings-interface': 1.2.2
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: false
/@serialport/bindings-cpp@11.0.1:
resolution: {integrity: sha512-3I1mniVg3osYuIUXxU0jB5AHPsxWmErmc3JC3WfUSlfXsjWMHkHfFzbW9Scuv/z/6DLCJIDyltabRa2FoW2qsQ==}
engines: {node: '>=14.0.0'}
requiresBuild: true
dependencies:
'@serialport/bindings-interface': 1.2.2
'@serialport/parser-readline': 10.5.0
debug: 4.3.4
node-addon-api: 6.1.0
node-gyp-build: 4.6.0
transitivePeerDependencies:
- supports-color
dev: false
/@serialport/bindings-interface@1.2.2:
resolution: {integrity: sha512-CJaUd5bLvtM9c5dmO9rPBHPXTa9R2UwpkJ0wdh9JCYcbrPWsKz+ErvR0hBLeo7NPeiFdjFO4sonRljiw4d2XiA==}
engines: {node: ^12.22 || ^14.13 || >=16}
dev: false
/@serialport/parser-byte-length@11.0.0:
resolution: {integrity: sha512-rExsdFKdzOIHOBqTwzxUF1A9nrluVIZKZOtvMq5i0Hc3euooGdmkx0VXYNRlI2rd6kJLTL2P+uIR+ZtCTRyT+w==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-cctalk@11.0.0:
resolution: {integrity: sha512-eN1MvEIFwI4GedWJhte6eWF+NZtrjchZbMf0CE6NV9TRzJI1KLnFf90ZOj/mhGuANojX4sqWfJKQXwN6E8VSHQ==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-delimiter@10.5.0:
resolution: {integrity: sha512-/uR/yT3jmrcwnl2FJU/2ySvwgo5+XpksDUR4NF/nwTS5i3CcuKS+FKi/tLzy1k8F+rCx5JzpiK+koqPqOUWArA==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-delimiter@11.0.0:
resolution: {integrity: sha512-aZLJhlRTjSmEwllLG7S4J8s8ctRAS0cbvCpO87smLvl3e4BgzbVgF6Z6zaJd3Aji2uSiYgfedCdNc4L6W+1E2g==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-inter-byte-timeout@11.0.0:
resolution: {integrity: sha512-RLgqZC50IET6FtEIt6Oi0vdRsesSBWLNwB7ldzR9OzyXKgK0XHRzqKqbB0u5Q+tC5OScdWeiQ2AO6jooKUZtsw==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-packet-length@11.0.0:
resolution: {integrity: sha512-6ZkOiaCooabpV/EM7ttSRbisbDWpGEf7Yxyr13t28LicYR43THRdjdMZcRnWxEM/jpwfskkLLXAR6wziVpKrlw==}
engines: {node: '>=8.6.0'}
dev: false
/@serialport/parser-readline@10.5.0:
resolution: {integrity: sha512-0aXJknodcl94W9zSjvU+sLdXiyEG2rqjQmvBWZCr8wJZjWEtv3RgrnYiWq4i2OTOyC8C/oPK8ZjpBjQptRsoJQ==}
engines: {node: '>=12.0.0'}
dependencies:
'@serialport/parser-delimiter': 10.5.0
dev: false
/@serialport/parser-readline@11.0.0:
resolution: {integrity: sha512-rRAivhRkT3YO28WjmmG4FQX6L+KMb5/ikhyylRfzWPw0nSXy97+u07peS9CbHqaNvJkMhH1locp2H36aGMOEIA==}
engines: {node: '>=12.0.0'}
dependencies:
'@serialport/parser-delimiter': 11.0.0
dev: false
/@serialport/parser-ready@11.0.0:
resolution: {integrity: sha512-lSsCPIctoc5kADCKnZDYBz1j69TsFqtnaWUicBzUAIAoUXpYKeYld8YX5NrvjViuVfIJeiqLZeGjxOWe5fqQqQ==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-regex@11.0.0:
resolution: {integrity: sha512-aKuc/+/KE9swahTbYpSuOsQa7LggPx7jhfobJLPVVbAic80OpfCIY+MKr6Ax4R6UtQwF90O5Yk6OEmbbvtEmiA==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-slip-encoder@11.0.0:
resolution: {integrity: sha512-3ZI/swd2it20vmu2tzqDbkyE4dqy+kExEDY6T33YQ210HDKPVhqj7FAVGo5P++MZ3dup1of11t4P9UPBNkuJnQ==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/parser-spacepacket@11.0.0:
resolution: {integrity: sha512-+hqRckrTEqz+/uAUZY0Tq6YIRyCl4oQOH1MeVzKiFiGNjZP7hDJCDoY7LTr9CeJhxvcT0ItTbtjGBqGumV8fxg==}
engines: {node: '>=12.0.0'}
dev: false
/@serialport/stream@11.0.0:
resolution: {integrity: sha512-Zty7B8C1H2XRnay2mVmW1ygEHXRHXQDcaC5wAVvOZMbQSc7ye03rMlPvviDS+pGxU2t2A2bMo34CUrRduSBong==}
engines: {node: '>=12.0.0'}
dependencies:
'@serialport/bindings-interface': 1.2.2
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: false
/@types/node@18.16.10:
resolution: {integrity: sha512-sMo3EngB6QkMBlB9rBe1lFdKSLqljyWPPWv6/FzSxh/IDlyVWSzE9RiF4eAuerQHybrWdqBgAGb03PM89qOasA==}
dev: true
/@types/serialport@8.0.2:
resolution: {integrity: sha512-z4b1I8/vdZE3upgCcAL9VAWlVVFUVn5uo3faAHavkVfK/Hb1LUxKwp9YCtA5AZqEUCWoSWl20SRTOvAI/5fQWQ==}
dependencies:
'@types/node': 18.16.10
dev: true
/abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
dev: false
/ansi-regex@2.1.1:
resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==}
engines: {node: '>=0.10.0'}
dev: false
/aproba@1.2.0:
resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==}
dev: false
/are-we-there-yet@1.1.7:
resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==}
dependencies:
delegates: 1.0.0
readable-stream: 2.3.8
dev: false
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: false
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: false
/chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: false
/code-point-at@1.1.0:
resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==}
engines: {node: '>=0.10.0'}
dev: false
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: false
/console-control-strings@1.1.0:
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
dev: false
/core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: false
/debug@3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.2
dev: false
/debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.2
dev: false
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
dev: false
/delegates@1.0.0:
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
dev: false
/detect-libc@1.0.3:
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
engines: {node: '>=0.10'}
hasBin: true
dev: false
/easy-sleep@1.2.2:
resolution: {integrity: sha512-mn+XCd6xKQWkLKnFFyg/3QZ2QvXqIFgUZNo/gWUYRilYHYdg9BdxPO0fPVWm+rhx3wzDaKJePK5tYC8x5aKIKg==}
requiresBuild: true
dependencies:
node-pre-gyp: 0.17.0
transitivePeerDependencies:
- supports-color
dev: false
/eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
dev: false
/fs-minipass@1.2.7:
resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==}
dependencies:
minipass: 2.9.0
dev: false
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: false
/gauge@2.7.4:
resolution: {integrity: sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==}
dependencies:
aproba: 1.2.0
console-control-strings: 1.1.0
has-unicode: 2.0.1
object-assign: 4.1.1
signal-exit: 3.0.7
string-width: 1.0.2
strip-ansi: 3.0.1
wide-align: 1.1.5
dev: false
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
dev: false
/has-unicode@2.0.1:
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
dev: false
/iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
dependencies:
safer-buffer: 2.1.2
dev: false
/ignore-walk@3.0.4:
resolution: {integrity: sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==}
dependencies:
minimatch: 3.1.2
dev: false
/inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: false
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: false
/ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
dev: false
/is-fullwidth-code-point@1.0.0:
resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==}
engines: {node: '>=0.10.0'}
dependencies:
number-is-nan: 1.0.1
dev: false
/isarray@1.0.0:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
dev: false
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
dev: false
/minipass@2.9.0:
resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==}
dependencies:
safe-buffer: 5.2.1
yallist: 3.1.1
dev: false
/minizlib@1.3.3:
resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==}
dependencies:
minipass: 2.9.0
dev: false
/mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
dependencies:
minimist: 1.2.8
dev: false
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: false
/needle@2.9.1:
resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==}
engines: {node: '>= 4.4.x'}
hasBin: true
dependencies:
debug: 3.2.7
iconv-lite: 0.4.24
sax: 1.2.4
transitivePeerDependencies:
- supports-color
dev: false
/node-addon-api@6.1.0:
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
dev: false
/node-gyp-build@4.6.0:
resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==}
hasBin: true
dev: false
/node-pre-gyp@0.17.0:
resolution: {integrity: sha512-abzZt1hmOjkZez29ppg+5gGqdPLUuJeAEwVPtHYEJgx0qzttCbcKFpxrCQn2HYbwCv2c+7JwH4BgEzFkUGpn4A==}
deprecated: 'Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future'
hasBin: true
dependencies:
detect-libc: 1.0.3
mkdirp: 0.5.6
needle: 2.9.1
nopt: 4.0.3
npm-packlist: 1.4.8
npmlog: 4.1.2
rc: 1.2.8
rimraf: 2.7.1
semver: 5.7.1
tar: 4.4.19
transitivePeerDependencies:
- supports-color
dev: false
/nopt@4.0.3:
resolution: {integrity: sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==}
hasBin: true
dependencies:
abbrev: 1.1.1
osenv: 0.1.5
dev: false
/npm-bundled@1.1.2:
resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==}
dependencies:
npm-normalize-package-bin: 1.0.1
dev: false
/npm-normalize-package-bin@1.0.1:
resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==}
dev: false
/npm-packlist@1.4.8:
resolution: {integrity: sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==}
dependencies:
ignore-walk: 3.0.4
npm-bundled: 1.1.2
npm-normalize-package-bin: 1.0.1
dev: false
/npmlog@4.1.2:
resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==}
dependencies:
are-we-there-yet: 1.1.7
console-control-strings: 1.1.0
gauge: 2.7.4
set-blocking: 2.0.0
dev: false
/number-is-nan@1.0.1:
resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==}
engines: {node: '>=0.10.0'}
dev: false
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: false
/os-homedir@1.0.2:
resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==}
engines: {node: '>=0.10.0'}
dev: false
/os-tmpdir@1.0.2:
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
dev: false
/osenv@0.1.5:
resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==}
dependencies:
os-homedir: 1.0.2
os-tmpdir: 1.0.2
dev: false
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
dev: false
/process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
dev: false
/rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
dev: false
/readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
dependencies:
core-util-is: 1.0.3
inherits: 2.0.4
isarray: 1.0.0
process-nextick-args: 2.0.1
safe-buffer: 5.1.2
string_decoder: 1.1.1
util-deprecate: 1.0.2
dev: false
/rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
hasBin: true
dependencies:
glob: 7.2.3
dev: false
/safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
dev: false
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
/safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false
/sax@1.2.4:
resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
dev: false
/semver@5.7.1:
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
hasBin: true
dev: false
/serialport@11.0.0:
resolution: {integrity: sha512-bxs3XejQcOHWpzPAaXMhxVRlbem6fjNUrux3ToqrGvFR6BcjOYhqE5CsHOuutv37kmhmnuHrn+/hN+1BpTmaFg==}
engines: {node: '>=12.0.0'}
dependencies:
'@serialport/binding-mock': 10.2.2
'@serialport/bindings-cpp': 11.0.1
'@serialport/parser-byte-length': 11.0.0
'@serialport/parser-cctalk': 11.0.0
'@serialport/parser-delimiter': 11.0.0
'@serialport/parser-inter-byte-timeout': 11.0.0
'@serialport/parser-packet-length': 11.0.0
'@serialport/parser-readline': 11.0.0
'@serialport/parser-ready': 11.0.0
'@serialport/parser-regex': 11.0.0
'@serialport/parser-slip-encoder': 11.0.0
'@serialport/parser-spacepacket': 11.0.0
'@serialport/stream': 11.0.0
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: false
/set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
dev: false
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: false
/string-width@1.0.2:
resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==}
engines: {node: '>=0.10.0'}
dependencies:
code-point-at: 1.1.0
is-fullwidth-code-point: 1.0.0
strip-ansi: 3.0.1
dev: false
/string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
dependencies:
safe-buffer: 5.1.2
dev: false
/strip-ansi@3.0.1:
resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==}
engines: {node: '>=0.10.0'}
dependencies:
ansi-regex: 2.1.1
dev: false
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
dev: false
/tar@4.4.19:
resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==}
engines: {node: '>=4.5'}
dependencies:
chownr: 1.1.4
fs-minipass: 1.2.7
minipass: 2.9.0
minizlib: 1.3.3
mkdirp: 0.5.6
safe-buffer: 5.2.1
yallist: 3.1.1
dev: false
/typescript@5.0.4:
resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
engines: {node: '>=12.20'}
hasBin: true
dev: true
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: false
/wide-align@1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
dependencies:
string-width: 1.0.2
dev: false
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: false
/yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
dev: false

View file

@ -1,5 +1,5 @@
import { EventEmitter } from "eventemitter3"
import SerialPort from "serialport"
import { SerialPort } from "serialport"
export const VENDOR_ID = "0403" // Enttec
export const PRODUCT_ID = "6001" // Open DMX USB
@ -9,21 +9,26 @@ interface Events {
error: [Error]
}
type Usleep = (microSeconds: number) => unknown
export class EnttecOpenDMXUSBDevice extends EventEmitter<Events> {
private shouldBeSending = false
private sendTimeout: ReturnType<typeof setTimeout> | null = null
private buffer = Buffer.alloc(513)
private readonly port: SerialPort
private readonly usleep: Usleep | null
/**
* @param {string} path A path returned by {@link EnttecOpenDMXUSBDevice.listDevices} or
* @param path A path returned by {@link EnttecOpenDMXUSBDevice.listDevices} or
* {@link EnttecOpenDMXUSBDevice.getFirstAvailableDevice}.
* @param {boolean} [startSending=true] Whether the device should start sending as soon as it is ready.
* @param [startSending=true] Whether the device should start sending as soon as it is ready.
* @param [usleep=null] A function blocking the event loop for `n` microseconds. See the README.md for more information.
*/
constructor(path: string, startSending = true) {
constructor(path: string, startSending = true, usleep: Usleep | null = null) {
super()
this.port = new SerialPort(path, {
this.port = new SerialPort({
path,
baudRate: 250000,
dataBits: 8,
stopBits: 2,
@ -40,12 +45,14 @@ export class EnttecOpenDMXUSBDevice extends EventEmitter<Events> {
this.port.on("error", (error: Error) => {
this.emit("error", error)
})
this.usleep = usleep
}
/**
* Start sending.
* @param {number} [interval=0] The time between each attempt to send. Most of the time, `0` works.
* @throws Error When the device is not ready yet.
* @param [interval=0] The milliseconds between each attempt to send. Most of the time `0` works fine.
* @throws When the device is not ready yet.
*/
startSending(interval = 0) {
if (!this.port.isOpen) throw new Error("The device is not ready yet. Wait for the 'ready' event.")
@ -54,7 +61,7 @@ export class EnttecOpenDMXUSBDevice extends EventEmitter<Events> {
// eslint-disable-next-line unicorn/consistent-function-scoping
const send = () => {
this.sendUniverse()
this._sendUniverse()
.then(() => {
if (this.shouldBeSending)
// eslint-disable-next-line @typescript-eslint/no-misused-promises
@ -76,11 +83,11 @@ export class EnttecOpenDMXUSBDevice extends EventEmitter<Events> {
}
/**
* Set the channel values.
* Set channel values.
* If channels is an Object, the keys are the channel numbers.
*
* @param {Buffer|Object|Array} channels
* @param {boolean} [clear=false] Whether all previously assigned channels should be set to 0
* @param channels
* @param [clear=false] Whether all previously assigned channels should be set to `0`
*/
setChannels(channels: Buffer | number[] | Record<number, number>, clear = false) {
if (clear) {
@ -119,26 +126,34 @@ export class EnttecOpenDMXUSBDevice extends EventEmitter<Events> {
}
/**
* @returns {Promise} Resolves when the whole universe was sent.
* @returns A Promise resolved when the whole universe was sent.
* @private
*/
private async sendUniverse(): Promise<void> {
async _sendUniverse(): Promise<void> {
return new Promise(resolve => {
this.port.set({ brk: true, rts: false }, () => {
setTimeout(() => {
if (this.usleep === null) {
setTimeout(() => {
this.port.set({ brk: false, rts: false }, () => {
setTimeout(() => {
this.port.write(this.buffer, () => resolve())
}, 1)
})
}, 1)
} else {
this.usleep(92)
this.port.set({ brk: false, rts: false }, () => {
setTimeout(() => {
this.port.write(this.buffer, () => resolve())
}, 0)
this.usleep!(12)
this.port.write(this.buffer, () => resolve())
})
}, 0)
}
})
})
}
/**
* Get the paths of all available devices.
* @returns {Promise<string[]>}
*/
static async listDevices(): Promise<string[]> {
const allPorts = await SerialPort.list()
@ -149,8 +164,7 @@ export class EnttecOpenDMXUSBDevice extends EventEmitter<Events> {
/**
* Get the path of the first available device.
* @throws Error When no device is found.
* @returns {Promise<string>}
* @throws When no device is found.
*/
static async getFirstAvailableDevice(): Promise<string> {
const devices = await EnttecOpenDMXUSBDevice.listDevices()

2323
yarn.lock

File diff suppressed because it is too large Load diff