diff --git a/package-lock.json b/package-lock.json index 20c22c3..2c84166 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,12 @@ "requires": true, "packages": { "": { + "name": "dmx", "version": "0.2.5", "license": "MIT", "dependencies": { "sacn": "^3.2.1", - "serialport": "^8.0.5", + "serialport": "^9.0.7", "socket.io": "^2.3.0" }, "devDependencies": { @@ -906,105 +907,146 @@ } }, "node_modules/@serialport/binding-abstract": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/binding-abstract/-/binding-abstract-8.0.6.tgz", - "integrity": "sha512-1swwUVoRyQ9ubxrkJ8JPppykohUpTAP4jkGr36e9NjbVocSPfqeX6tFZFwl/IdUlwJwxGdbKDqq7FvXniCQUMw==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/binding-abstract/-/binding-abstract-9.0.7.tgz", + "integrity": "sha512-g1ncCMIG9rMsxo/28ObYmXZcHThlvtZygsCANmyMUuFS7SwXY4+PhcEnt2+ZcMkEDNRiOklT+ngtIVx5GGpt/A==", "dependencies": { - "debug": "^4.1.1" + "debug": "^4.3.1" }, "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/binding-mock": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-8.0.6.tgz", - "integrity": "sha512-BIbY5/PsDDo0QWDNCCxDgpowAdks+aZR8BOsEtK2GoASTTcJCy1fBwPIfH870o7rnbH901wY3C+yuTfdOvSO9A==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-9.0.7.tgz", + "integrity": "sha512-aR8H+htZwwZZkVb1MdbnNvGWw8eXVRqQ2qPhkbKyx0N/LY5aVIgCgT98Kt1YylLsG7SzNG+Jbhd4wzwEuPVT5Q==", "dependencies": { - "@serialport/binding-abstract": "^8.0.6", - "debug": "^4.1.1" + "@serialport/binding-abstract": "^9.0.7", + "debug": "^4.3.1" }, "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/bindings": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/@serialport/bindings/-/bindings-8.0.8.tgz", - "integrity": "sha512-xMJHr7CyOPq+wwC/S2RNI+tY+WZW4gXY3tE8QUOIRp0K7lSyLYOzKdyGUtk2uI0ohDMV3OcB+TEhhffT2S2DHQ==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/bindings/-/bindings-9.0.7.tgz", + "integrity": "sha512-cNWaxnEbbpLoSJ6GMb0ZeCpaciczm8XRE4jgBqe/BflWZb+wyiTYIocbsySxpS40WT3kJ0sNTFag77uSmQ6ftg==", "hasInstallScript": true, "dependencies": { - "@serialport/binding-abstract": "^8.0.6", - "@serialport/parser-readline": "^8.0.6", + "@serialport/binding-abstract": "^9.0.7", + "@serialport/parser-readline": "^9.0.7", "bindings": "^1.5.0", - "debug": "^4.1.1", - "nan": "^2.14.0", - "prebuild-install": "^5.3.0" + "debug": "^4.3.1", + "nan": "^2.14.2", + "prebuild-install": "^6.0.1" }, "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/parser-byte-length": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-8.0.6.tgz", - "integrity": "sha512-92mrFxFEvq3gRvSM7ANK/jfbmHslz91a5oYJy/nbSn4H/MCRXjxR2YOkQgVXuN+zLt+iyDoW3pcOP4Sc1nWdqQ==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-9.0.7.tgz", + "integrity": "sha512-evf7oOOSBMBn2AZZbgBFMRIyEzlsyQkhqaPm7IBCPTxMDXRf4tKkFYJHYZB0/6d1W4eI0meH079UqmSsh/uoDA==", "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/parser-cctalk": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-8.0.6.tgz", - "integrity": "sha512-pqtCYQPgxnxHygiXUPCfgX7sEx+fdR/ObjpscidynEULUq2fFrC5kBkrxRbTfHRtTaU2ii9DyjFq0JVRCbhI0Q==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-9.0.7.tgz", + "integrity": "sha512-ert5jhMkeiTfr44TkbdySC09J8UwAsf/RxBucVN5Mz5enG509RggnkfFi4mfj3UCG2vZ7qsmM6gtZ62DshY02Q==", "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/parser-delimiter": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-8.0.6.tgz", - "integrity": "sha512-ogKOcPisPMlVtirkuDu3SFTF0+xT0ijxoH7XjpZiYL41EVi367MwuCnEmXG+dEKKnF0j9EPqOyD2LGSJxaFmhQ==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-9.0.7.tgz", + "integrity": "sha512-Vb2NPeXPZ/28M4m5x4OAHFd8jRAeddNCgvL+Q+H/hqFPY1w47JcMLchC7pigRW8Cnt1fklmzfwdNQ8Fb+kMkxQ==", "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-inter-byte-timeout": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-inter-byte-timeout/-/parser-inter-byte-timeout-9.0.7.tgz", + "integrity": "sha512-lUZ3cwgUluBvJ1jf+0LQsqoiPYAokDO6+fRCw9HCfnrF/OS60Gm4rxuyo2uQIueqZkJ7NIFP+ibKsULrA47AEA==", + "engines": { + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/parser-readline": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-8.0.6.tgz", - "integrity": "sha512-OYBT2mpczh9QUI3MTw8j0A0tIlPVjpVipvuVnjRkYwxrxPeq04RaLFhaDpuRzua5rTKMt89c1y3btYeoDXMjAA==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-9.0.7.tgz", + "integrity": "sha512-ydoLbgVQQPxWrwbe3Fhh4XnZexbkEQAC6M/qgRTzjnKvTjrD61CJNxLc3vyDaAPI9bJIhTiI7eTX3JB5jJv8Hg==", "dependencies": { - "@serialport/parser-delimiter": "^8.0.6" + "@serialport/parser-delimiter": "^9.0.7" }, "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/parser-ready": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-8.0.6.tgz", - "integrity": "sha512-xcEqv4rc119WR5JzAuu8UeJOlAwET2PTdNb6aIrrLlmTxhvuBbuRFcsnF3BpH9jUL30Kh7a6QiNXIwVG+WR/1Q==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-9.0.7.tgz", + "integrity": "sha512-3qYhI4cNUPAYqVYvdwV57Y+PVRl4dJf1fPBtMoWtwDgwopsAXTR93WCs49WuUq9JCyNW+8Hrfqv8x8eNAD5Dqg==", "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/parser-regex": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-8.0.6.tgz", - "integrity": "sha512-J8KY75Azz5ZyExmyM5YfUxbXOWBkZCytKgCCmZ966ttwZS0bUZOuoCaZj2Zp4VILJAiLuxHoqc0foi67Fri5+g==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-9.0.7.tgz", + "integrity": "sha512-5XF+FXbhqQ/5bVKM4NaGs1m+E9KjfmeCx/obwsKaUZognQF67jwoTfjJJWNP/21jKfxdl8XoCYjZjASl3XKRAw==", "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@serialport/stream": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-8.0.6.tgz", - "integrity": "sha512-ym1PwM0rwLrj90vRBB66I1hwMXbuMw9wGTxqns75U3N/tuNFOH85mxXaYVF2TpI66aM849NoI1jMm50fl9equg==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-9.0.7.tgz", + "integrity": "sha512-c/h7HPAeFiryD9iTGlaSvPqHFHSZ0NMQHxC4rcmKS2Vu3qJuEtkBdTLABwsMp7iWEiSnI4KC3s7bHapaXP06FQ==", "dependencies": { - "debug": "^4.1.1" + "debug": "^4.3.1" }, "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/@types/babel__core": { @@ -7037,9 +7079,9 @@ "dev": true }, "node_modules/node-abi": { - "version": "2.19.3", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz", - "integrity": "sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg==", + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.21.0.tgz", + "integrity": "sha512-smhrivuPqEM3H5LmnY3KU6HfYv0u4QklgAxfFyRNujKUzbUcYZ+Jc2EhukB9SRcD2VpqhxM7n/MIcp1Ua1/JMg==", "dependencies": { "semver": "^5.4.1" } @@ -7666,9 +7708,9 @@ } }, "node_modules/prebuild-install": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", - "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.0.1.tgz", + "integrity": "sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==", "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -8533,24 +8575,27 @@ } }, "node_modules/serialport": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/serialport/-/serialport-8.0.8.tgz", - "integrity": "sha512-GEaMYbAk9chfGyxoVC27PHnKMUMOQOCAg+9umOhAgk88vH0H6DbQ9/Tj3lRwoj7lE+TLra75P/0l1RXMfX4yQg==", - "hasInstallScript": true, - "dependencies": { - "@serialport/binding-mock": "^8.0.6", - "@serialport/bindings": "^8.0.8", - "@serialport/parser-byte-length": "^8.0.6", - "@serialport/parser-cctalk": "^8.0.6", - "@serialport/parser-delimiter": "^8.0.6", - "@serialport/parser-readline": "^8.0.6", - "@serialport/parser-ready": "^8.0.6", - "@serialport/parser-regex": "^8.0.6", - "@serialport/stream": "^8.0.6", - "debug": "^4.1.1" + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/serialport/-/serialport-9.0.7.tgz", + "integrity": "sha512-NeDfVks3JAJ7s8cXDopx1iUUgC/7TaltE7iQGiSewIWMZaK7oStiz3VJzcuKgor7F+U/y6zbAnj4i6eHq0on+g==", + "dependencies": { + "@serialport/binding-mock": "^9.0.7", + "@serialport/bindings": "^9.0.7", + "@serialport/parser-byte-length": "^9.0.7", + "@serialport/parser-cctalk": "^9.0.7", + "@serialport/parser-delimiter": "^9.0.7", + "@serialport/parser-inter-byte-timeout": "^9.0.7", + "@serialport/parser-readline": "^9.0.7", + "@serialport/parser-ready": "^9.0.7", + "@serialport/parser-regex": "^9.0.7", + "@serialport/stream": "^9.0.7", + "debug": "^4.3.1" }, "engines": { - "node": ">=8.6.0" + "node": ">=10.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" } }, "node_modules/set-blocking": { @@ -11259,74 +11304,79 @@ } }, "@serialport/binding-abstract": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/binding-abstract/-/binding-abstract-8.0.6.tgz", - "integrity": "sha512-1swwUVoRyQ9ubxrkJ8JPppykohUpTAP4jkGr36e9NjbVocSPfqeX6tFZFwl/IdUlwJwxGdbKDqq7FvXniCQUMw==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/binding-abstract/-/binding-abstract-9.0.7.tgz", + "integrity": "sha512-g1ncCMIG9rMsxo/28ObYmXZcHThlvtZygsCANmyMUuFS7SwXY4+PhcEnt2+ZcMkEDNRiOklT+ngtIVx5GGpt/A==", "requires": { - "debug": "^4.1.1" + "debug": "^4.3.1" } }, "@serialport/binding-mock": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-8.0.6.tgz", - "integrity": "sha512-BIbY5/PsDDo0QWDNCCxDgpowAdks+aZR8BOsEtK2GoASTTcJCy1fBwPIfH870o7rnbH901wY3C+yuTfdOvSO9A==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-9.0.7.tgz", + "integrity": "sha512-aR8H+htZwwZZkVb1MdbnNvGWw8eXVRqQ2qPhkbKyx0N/LY5aVIgCgT98Kt1YylLsG7SzNG+Jbhd4wzwEuPVT5Q==", "requires": { - "@serialport/binding-abstract": "^8.0.6", - "debug": "^4.1.1" + "@serialport/binding-abstract": "^9.0.7", + "debug": "^4.3.1" } }, "@serialport/bindings": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/@serialport/bindings/-/bindings-8.0.8.tgz", - "integrity": "sha512-xMJHr7CyOPq+wwC/S2RNI+tY+WZW4gXY3tE8QUOIRp0K7lSyLYOzKdyGUtk2uI0ohDMV3OcB+TEhhffT2S2DHQ==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/bindings/-/bindings-9.0.7.tgz", + "integrity": "sha512-cNWaxnEbbpLoSJ6GMb0ZeCpaciczm8XRE4jgBqe/BflWZb+wyiTYIocbsySxpS40WT3kJ0sNTFag77uSmQ6ftg==", "requires": { - "@serialport/binding-abstract": "^8.0.6", - "@serialport/parser-readline": "^8.0.6", + "@serialport/binding-abstract": "^9.0.7", + "@serialport/parser-readline": "^9.0.7", "bindings": "^1.5.0", - "debug": "^4.1.1", - "nan": "^2.14.0", - "prebuild-install": "^5.3.0" + "debug": "^4.3.1", + "nan": "^2.14.2", + "prebuild-install": "^6.0.1" } }, "@serialport/parser-byte-length": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-8.0.6.tgz", - "integrity": "sha512-92mrFxFEvq3gRvSM7ANK/jfbmHslz91a5oYJy/nbSn4H/MCRXjxR2YOkQgVXuN+zLt+iyDoW3pcOP4Sc1nWdqQ==" + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-9.0.7.tgz", + "integrity": "sha512-evf7oOOSBMBn2AZZbgBFMRIyEzlsyQkhqaPm7IBCPTxMDXRf4tKkFYJHYZB0/6d1W4eI0meH079UqmSsh/uoDA==" }, "@serialport/parser-cctalk": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-8.0.6.tgz", - "integrity": "sha512-pqtCYQPgxnxHygiXUPCfgX7sEx+fdR/ObjpscidynEULUq2fFrC5kBkrxRbTfHRtTaU2ii9DyjFq0JVRCbhI0Q==" + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-9.0.7.tgz", + "integrity": "sha512-ert5jhMkeiTfr44TkbdySC09J8UwAsf/RxBucVN5Mz5enG509RggnkfFi4mfj3UCG2vZ7qsmM6gtZ62DshY02Q==" }, "@serialport/parser-delimiter": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-8.0.6.tgz", - "integrity": "sha512-ogKOcPisPMlVtirkuDu3SFTF0+xT0ijxoH7XjpZiYL41EVi367MwuCnEmXG+dEKKnF0j9EPqOyD2LGSJxaFmhQ==" + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-9.0.7.tgz", + "integrity": "sha512-Vb2NPeXPZ/28M4m5x4OAHFd8jRAeddNCgvL+Q+H/hqFPY1w47JcMLchC7pigRW8Cnt1fklmzfwdNQ8Fb+kMkxQ==" + }, + "@serialport/parser-inter-byte-timeout": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-inter-byte-timeout/-/parser-inter-byte-timeout-9.0.7.tgz", + "integrity": "sha512-lUZ3cwgUluBvJ1jf+0LQsqoiPYAokDO6+fRCw9HCfnrF/OS60Gm4rxuyo2uQIueqZkJ7NIFP+ibKsULrA47AEA==" }, "@serialport/parser-readline": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-8.0.6.tgz", - "integrity": "sha512-OYBT2mpczh9QUI3MTw8j0A0tIlPVjpVipvuVnjRkYwxrxPeq04RaLFhaDpuRzua5rTKMt89c1y3btYeoDXMjAA==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-9.0.7.tgz", + "integrity": "sha512-ydoLbgVQQPxWrwbe3Fhh4XnZexbkEQAC6M/qgRTzjnKvTjrD61CJNxLc3vyDaAPI9bJIhTiI7eTX3JB5jJv8Hg==", "requires": { - "@serialport/parser-delimiter": "^8.0.6" + "@serialport/parser-delimiter": "^9.0.7" } }, "@serialport/parser-ready": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-8.0.6.tgz", - "integrity": "sha512-xcEqv4rc119WR5JzAuu8UeJOlAwET2PTdNb6aIrrLlmTxhvuBbuRFcsnF3BpH9jUL30Kh7a6QiNXIwVG+WR/1Q==" + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-9.0.7.tgz", + "integrity": "sha512-3qYhI4cNUPAYqVYvdwV57Y+PVRl4dJf1fPBtMoWtwDgwopsAXTR93WCs49WuUq9JCyNW+8Hrfqv8x8eNAD5Dqg==" }, "@serialport/parser-regex": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-8.0.6.tgz", - "integrity": "sha512-J8KY75Azz5ZyExmyM5YfUxbXOWBkZCytKgCCmZ966ttwZS0bUZOuoCaZj2Zp4VILJAiLuxHoqc0foi67Fri5+g==" + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-9.0.7.tgz", + "integrity": "sha512-5XF+FXbhqQ/5bVKM4NaGs1m+E9KjfmeCx/obwsKaUZognQF67jwoTfjJJWNP/21jKfxdl8XoCYjZjASl3XKRAw==" }, "@serialport/stream": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-8.0.6.tgz", - "integrity": "sha512-ym1PwM0rwLrj90vRBB66I1hwMXbuMw9wGTxqns75U3N/tuNFOH85mxXaYVF2TpI66aM849NoI1jMm50fl9equg==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-9.0.7.tgz", + "integrity": "sha512-c/h7HPAeFiryD9iTGlaSvPqHFHSZ0NMQHxC4rcmKS2Vu3qJuEtkBdTLABwsMp7iWEiSnI4KC3s7bHapaXP06FQ==", "requires": { - "debug": "^4.1.1" + "debug": "^4.3.1" } }, "@types/babel__core": { @@ -16157,9 +16207,9 @@ "dev": true }, "node-abi": { - "version": "2.19.3", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz", - "integrity": "sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg==", + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.21.0.tgz", + "integrity": "sha512-smhrivuPqEM3H5LmnY3KU6HfYv0u4QklgAxfFyRNujKUzbUcYZ+Jc2EhukB9SRcD2VpqhxM7n/MIcp1Ua1/JMg==", "requires": { "semver": "^5.4.1" }, @@ -16645,9 +16695,9 @@ "dev": true }, "prebuild-install": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", - "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.0.1.tgz", + "integrity": "sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==", "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -17311,20 +17361,21 @@ } }, "serialport": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/serialport/-/serialport-8.0.8.tgz", - "integrity": "sha512-GEaMYbAk9chfGyxoVC27PHnKMUMOQOCAg+9umOhAgk88vH0H6DbQ9/Tj3lRwoj7lE+TLra75P/0l1RXMfX4yQg==", - "requires": { - "@serialport/binding-mock": "^8.0.6", - "@serialport/bindings": "^8.0.8", - "@serialport/parser-byte-length": "^8.0.6", - "@serialport/parser-cctalk": "^8.0.6", - "@serialport/parser-delimiter": "^8.0.6", - "@serialport/parser-readline": "^8.0.6", - "@serialport/parser-ready": "^8.0.6", - "@serialport/parser-regex": "^8.0.6", - "@serialport/stream": "^8.0.6", - "debug": "^4.1.1" + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/serialport/-/serialport-9.0.7.tgz", + "integrity": "sha512-NeDfVks3JAJ7s8cXDopx1iUUgC/7TaltE7iQGiSewIWMZaK7oStiz3VJzcuKgor7F+U/y6zbAnj4i6eHq0on+g==", + "requires": { + "@serialport/binding-mock": "^9.0.7", + "@serialport/bindings": "^9.0.7", + "@serialport/parser-byte-length": "^9.0.7", + "@serialport/parser-cctalk": "^9.0.7", + "@serialport/parser-delimiter": "^9.0.7", + "@serialport/parser-inter-byte-timeout": "^9.0.7", + "@serialport/parser-readline": "^9.0.7", + "@serialport/parser-ready": "^9.0.7", + "@serialport/parser-regex": "^9.0.7", + "@serialport/stream": "^9.0.7", + "debug": "^4.3.1" } }, "set-blocking": { diff --git a/package.json b/package.json index a34327f..909464d 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ ], "dependencies": { "sacn": "^3.2.1", - "serialport": "^8.0.5", + "serialport": "^9.0.7", "socket.io": "^2.3.0" }, "devDependencies": { diff --git a/readme.md b/readme.md index 57b526c..bd37595 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,9 @@ DMX-512 controller library for node.js ## Install - npm install dmx +```bash +npm install dmx +``` ## Library API ```javascript diff --git a/spec/anim.spec.ts b/spec/anim.spec.ts index eade31a..2812127 100644 --- a/spec/anim.spec.ts +++ b/spec/anim.spec.ts @@ -1,48 +1,60 @@ -import {DMX, Animation} from '../src'; -import { NullDriver } from '../src/drivers/null'; +import {Animation, DMX} from '../src'; +import {NullDriver} from '../src/drivers/null'; +import {IUniverseDriver} from '../src/models/IUniverseDriver'; -const dmx = new DMX(); -const universe = dmx.addUniverse('test', new NullDriver()); +describe('Animations', () => { -const updateMock = jest.fn(); + let dmx: DMX; + let universeDriver: IUniverseDriver; -universe.update = updateMock; -universe.update({ 1: 255 }); + beforeEach(async () => { + dmx = new DMX(); + universeDriver = new NullDriver(); + await dmx.addUniverse('test', universeDriver); + }); -const ANIM_PRECISION = 50; + const ANIM_PRECISION = 50; -test('fake timers', () => { - jest.useFakeTimers(); + test('fake timers', () => { + const updateMock = jest.fn(); - new Animation().add({ - 1: 255, - }, 100).add({ - 1: 0, - }, 100).run(universe); + universeDriver.update = updateMock; + universeDriver.update({1: 255}); - jest.runAllTimers(); + jest.useFakeTimers(); - expect(updateMock).toHaveBeenCalledWith({ 1: 255 }, { origin: 'animation' }); - expect(updateMock).toHaveBeenCalledWith({ 1: 0 }, { origin: 'animation' }); -}); + new Animation().add({ + 1: 255, + }, 100).add({ + 1: 0, + }, 100).run(universeDriver); -test('real timers', done => { - jest.useRealTimers(); + jest.runAllTimers(); - const startAt = Date.now(); + expect(updateMock).toHaveBeenCalledWith({1: 255}, {origin: 'animation'}); + expect(updateMock).toHaveBeenCalledWith({1: 0}, {origin: 'animation'}); + }); - new Animation().add({ - 1: 255, - }, 250).add({ - 1: 0, - }, 250).run(universe, async () => { - await universe.stop(); - await universe.close(); - const timeTook = Date.now() - startAt; + test('real timers', done => { + universeDriver.update = jest.fn(); + universeDriver.update({1: 255}); - expect(timeTook).toBeGreaterThanOrEqual(500 - ANIM_PRECISION); - expect(timeTook).toBeLessThanOrEqual(500 + ANIM_PRECISION); - done(); - }); + jest.useRealTimers(); + const startAt = Date.now(); + + new Animation().add({ + 1: 255, + }, 250).add({ + 1: 0, + }, 250).run(universeDriver, async () => { + await universeDriver.close(); + const timeTook = Date.now() - startAt; + + expect(timeTook).toBeGreaterThanOrEqual(500 - ANIM_PRECISION); + expect(timeTook).toBeLessThanOrEqual(500 + ANIM_PRECISION); + done(); + }); + + }); }); diff --git a/src/DMX.ts b/src/DMX.ts index 770663e..7561405 100644 --- a/src/DMX.ts +++ b/src/DMX.ts @@ -17,7 +17,9 @@ export class DMX extends EventEmitter { this._devices = Object.assign({}, PredefinedDevices, devices); } - addUniverse(name: string, universe: IUniverseDriver): IUniverseDriver { + async addUniverse(name: string, universe: IUniverseDriver): Promise { + await universe.init(); + universe.on(Events.update, (channels, extraData) => { this.emit(Events.update, name, channels, extraData); }); @@ -27,8 +29,12 @@ export class DMX extends EventEmitter { return universe; } - update(universe: string, channels: {[key: number]: number}, extraData?: any): void { - this._universesByName.get(universe)?.update(channels, extraData || {}); + update(universeName: string, channels: {[key: number]: number}, extraData?: any): void { + const universe = this._universesByName.get( universeName ); + if ( universe === undefined ) { + throw new Error( `Universe ${universe} does not exist` ); + } + universe.update( channels, extraData || {} ); } updateAll(universe: string, value: number): void { @@ -51,5 +57,6 @@ export class DMX extends EventEmitter { for (const uni of this._universesByName.values()) { await uni.close(); } + this.removeAllListeners(); } } diff --git a/src/demo/demo.ts b/src/demo/demo.ts index 7f0cb19..3d44254 100644 --- a/src/demo/demo.ts +++ b/src/demo/demo.ts @@ -1,86 +1,57 @@ -import { Animation } from '../Animation'; -import { NullDriver } from '../drivers/null'; -import { DMX } from '../'; -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; - -const dmx = new DMX(); - -// var universe = dmx.addUniverse('demo', 'enttec-usb-dmx-pro', '/dev/cu.usbserial-6AVNHXS8') -// var universe = dmx.addUniverse('demo', 'enttec-open-usb-dmx', '/dev/cu.usbserial-6AVNHXS8') -// const universe = dmx.addUniverse('demo', 'socketio', null, {port: 17809, debug: true}); -const universe = dmx.addUniverse('demo', new NullDriver()); - -universe.update({1: 1, 2: 0}); -universe.update({16: 1, 17: 255}); -universe.update({1: 255, 3: 120, 4: 230, 5: 30, 6: 110, 7: 255, 8: 10, 9: 255, 10: 255, 11: 0}); - -function greenWater(universe: IUniverseDriver, channels: UniverseData, duration: number): void { - const colors = [ - [160, 230, 20], - [255, 255, 0], - [110, 255, 10], - ]; - - for (const c in channels) { - const r = Math.floor((Math.random() * colors.length)); - const u: UniverseData = {}; - - for (let i = 0; i < 3; i++) { - u[channels[c] + i] = colors[r][i]; +import {Animation} from '../Animation'; +import {NullDriver} from '../drivers/null'; +import {DMX} from '../'; +import {IUniverseDriver, UniverseData} from '../models/IUniverseDriver'; + +const run = async () => { + + const dmx = new DMX(); + + // var universe = dmx.addUniverse('demo', 'enttec-usb-dmx-pro', '/dev/cu.usbserial-6AVNHXS8') + // var universe = dmx.addUniverse('demo', 'enttec-open-usb-dmx', '/dev/cu.usbserial-6AVNHXS8') + // const universe = dmx.addUniverse('demo', 'socketio', null, {port: 17809, debug: true}); + const universe = await dmx.addUniverse('demo', new NullDriver()); + + universe.update({1: 1, 2: 0}); + universe.update({16: 1, 17: 255}); + universe.update({1: 255, 3: 120, 4: 230, 5: 30, 6: 110, 7: 255, 8: 10, 9: 255, 10: 255, 11: 0}); + + function greenWater(universe: IUniverseDriver, channels: UniverseData, duration: number): void { + const colors = [ + [160, 230, 20], + [255, 255, 0], + [110, 255, 10], + ]; + + for (const c in channels) { + const r = Math.floor((Math.random() * colors.length)); + const u: UniverseData = {}; + + for (let i = 0; i < 3; i++) { + u[channels[c] + i] = colors[r][i]; + } + new Animation().add(u, duration).run(universe); } - new Animation().add(u, duration).run(universe); + setTimeout(() => greenWater(universe, channels, duration), duration * 2); } - setTimeout(() => greenWater(universe, channels, duration), duration * 2); -} -function warp(universe: IUniverseDriver, channel: number, min: number, max: number, duration: number): void { - const a: UniverseData = {}; - const b: UniverseData = {}; + function warp(universe: IUniverseDriver, channel: number, min: number, max: number, duration: number): void { + const a: UniverseData = {}; + const b: UniverseData = {}; - a[channel] = min; - b[channel] = max; - new Animation().add(a, duration).add(b, duration).run(universe, function () { - warp(universe, channel, min, max, duration); - }); -} - -warp(universe, 1, 200, 220, 360); -warp(universe, 1 + 15, 200, 255, 240); -greenWater(universe, [3, 6, 9], 4000); -greenWater(universe, [3 + 15, 6 + 15, 9 + 15], 4000); + a[channel] = min; + b[channel] = max; + new Animation().add(a, duration).add(b, duration).run(universe, function () { + warp(universe, channel, min, max, duration); + }); + } -// function done() { console.log('DONE'); } -// -// const x = new A() -// .add({1: 255, 6: 110, 7: 255, 8: 10}, 1200) -// .delay(1000) -// .add({1: 0}, 600) -// .add({1: 255}, 600) -// .add({5: 255, 6: 128}, 1000) -// .add({1: 0}, 100) -// .add({1: 255}, 100) -// .add({1: 0}, 200) -// .add({1: 255}, 200) -// .add({1: 0}, 100) -// .add({1: 255}, 100) -// .add({1: 0}) -// .delay(50) -// .add({1: 255}) -// .delay(50) -// .add({1: 0}) -// .delay(50) -// .add({1: 255}) -// .delay(50) -// .add({1: 0}) -// .delay(50) -// .add({1: 255}) -// .delay(50) -// .add({2: 255}, 6000) -// .delay(200) -// .add({2: 0}); + warp(universe, 1, 200, 220, 360); + warp(universe, 1 + 15, 200, 255, 240); + greenWater(universe, [3, 6, 9], 4000); + greenWater(universe, [3 + 15, 6 + 15, 9 + 15], 4000); -// const y = new A() -// .add({9: 255}, 10000); +}; -// x.run(universe, done); -// y.run(universe, done); +run() + .catch((err) => console.error(err)); diff --git a/src/demo/demo_simple.ts b/src/demo/demo_simple.ts index 33ea9ec..34f5948 100644 --- a/src/demo/demo_simple.ts +++ b/src/demo/demo_simple.ts @@ -1,22 +1,27 @@ -import { NullDriver } from '../drivers/null'; +import {NullDriver} from '../drivers/null'; import {DMX} from '../index'; const dmx = new DMX(); // var universe = dmx.addUniverse('demo', 'enttec-open-usb-dmx', '/dev/cu.usbserial-6AVNHXS8') // const universe = dmx.addUniverse('demo', 'socketio', null, {port: 17809, debug: true}); -const universe = dmx.addUniverse('demo', new NullDriver()); +const run = async () => { + const universe = await dmx.addUniverse('demo', new NullDriver()); -let on = false; + let on = false; -setInterval(() => { - if (on) { - on = false; - universe.updateAll(0); - console.log('off'); - } else { - on = true; - universe.updateAll(250); - console.log('on'); - } -}, 1000); + setInterval(() => { + if (on) { + on = false; + universe.updateAll(0); + console.log('off'); + } else { + on = true; + universe.updateAll(250); + console.log('on'); + } + }, 1000); +}; + +run() + .catch((err) => console.error(err)); diff --git a/src/drivers/abstract-serial-driver.ts b/src/drivers/abstract-serial-driver.ts new file mode 100644 index 0000000..ff98fcb --- /dev/null +++ b/src/drivers/abstract-serial-driver.ts @@ -0,0 +1,89 @@ +import {EventEmitter} from 'events'; +import SerialPort from 'serialport'; +import {IUniverseDriver, UniverseData} from '../models/IUniverseDriver'; + +export interface AbstractSerialDriverArgs { + serialPortOptions: SerialPort.OpenOptions; + sendInterval: number; +} + +export abstract class AbstractSerialDriver extends EventEmitter implements IUniverseDriver { + private _serialPort!: SerialPort; + + private readonly _universe: Buffer; + private readonly _sendInterval: number; + private readonly _serialPortName: string; + private readonly _serialPortOptions: SerialPort.OpenOptions; + private _intervalHandle: any | undefined = undefined; + + protected constructor(serialPort: string, args: AbstractSerialDriverArgs) { + super(); + this._sendInterval = args.sendInterval; + this._serialPortName = serialPort; + this._serialPortOptions = args.serialPortOptions; + + this._universe = Buffer.alloc(513); + } + + init(): Promise { + return new Promise((resolve, reject) => { + this._serialPort = new SerialPort(this._serialPortName, this._serialPortOptions, (err) => { + if (!err) { + this.start(); + resolve(); + } else { + reject(err); + } + }); + }); + } + + close(): Promise { + this.stop(); + return new Promise((resolve, reject) => this._serialPort.close((err: any) => err ? reject(err) : resolve())); + } + + protected get serialPort(): SerialPort { + return this._serialPort; + } + + protected get universeBuffer(): Buffer { + return this._universe; + } + + protected start(): void { + if (this._intervalHandle !== undefined) { + throw new Error('Driver is already running.'); + } + this._intervalHandle = setInterval(this.sendUniverse.bind(this), this._sendInterval); + } + + protected stop(): void { + if (this._intervalHandle !== undefined) { + clearInterval(this._intervalHandle); + this._intervalHandle = undefined; + } + } + + protected abstract sendUniverse(): Promise; + + get(channel: number): number { + return this._universe[channel]; + } + + update(channels: UniverseData, extraData?: any): void { + + for (const c in channels) { + this._universe[c] = channels[c]; + } + + this.emit('update', channels, extraData); + } + + updateAll(value: number): void { + for (let i = 1; i <= 512; i++) { + this._universe[i] = value; + } + } + +} diff --git a/src/drivers/artnet.ts b/src/drivers/artnet.ts index 60540a1..46d83fd 100644 --- a/src/drivers/artnet.ts +++ b/src/drivers/artnet.ts @@ -1,5 +1,5 @@ -import { EventEmitter } from 'events'; -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; +import {EventEmitter} from 'events'; +import {IUniverseDriver, UniverseData} from '../models/IUniverseDriver'; import dgram from 'dgram'; export interface ArtnetArgs { @@ -21,6 +21,7 @@ export class ArtnetDriver extends EventEmitter implements IUniverseDriver { port: any; dev: any; timeout?: any; + constructor(deviceId = '127.0.0.1', options: ArtnetArgs = {}) { super(); this.readyToWrite = true; @@ -44,6 +45,9 @@ export class ArtnetDriver extends EventEmitter implements IUniverseDriver { this.port = options.port || 6454; this.dev = dgram.createSocket('udp4'); this.dev.bind(() => this.dev.setBroadcast(true)); + } + + async init(): Promise { this.start(); } @@ -65,14 +69,6 @@ export class ArtnetDriver extends EventEmitter implements IUniverseDriver { } } - start(): void { - this.timeout = setInterval(this.sendUniverse.bind(this), this.interval); - } - - stop(): void { - if (this.timeout) clearInterval(this.timeout); - } - close(): Promise { return new Promise((resolve) => { this.stop(); @@ -97,4 +93,12 @@ export class ArtnetDriver extends EventEmitter implements IUniverseDriver { get(c: number): number { return this.universe[c]; } + + private start(): void { + this.timeout = setInterval(this.sendUniverse.bind(this), this.interval); + } + + private stop(): void { + if (this.timeout) clearInterval(this.timeout); + } } diff --git a/src/drivers/bbdmx.ts b/src/drivers/bbdmx.ts index 68969c1..384bf87 100644 --- a/src/drivers/bbdmx.ts +++ b/src/drivers/bbdmx.ts @@ -1,5 +1,5 @@ -import { EventEmitter } from 'events'; -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; +import {EventEmitter} from 'events'; +import {IUniverseDriver, UniverseData} from '../models/IUniverseDriver'; const dgram = require('dgram'); @@ -19,6 +19,7 @@ export class BBDMXDriver extends EventEmitter implements IUniverseDriver { host: string; port: any; dev: any; + constructor(deviceId = '127.0.0.1', options: BBDMXArgs = {}) { super(); this.readyToWrite = true; @@ -31,6 +32,10 @@ export class BBDMXDriver extends EventEmitter implements IUniverseDriver { this.start(); } + async init(): Promise { + this.start(); + } + sendUniverse(): void { if (this.readyToWrite) { this.readyToWrite = false; @@ -49,14 +54,6 @@ export class BBDMXDriver extends EventEmitter implements IUniverseDriver { } } - start(): void { - this.timeout = setInterval(this.sendUniverse.bind(this), this.interval); - } - - stop(): void { - if (this.timeout) clearInterval(this.timeout); - } - close(): void { this.stop(); } @@ -78,4 +75,12 @@ export class BBDMXDriver extends EventEmitter implements IUniverseDriver { get(c: number): number { return this.universe[c]; } + + private start(): void { + this.timeout = setInterval(this.sendUniverse.bind(this), this.interval); + } + + private stop(): void { + if (this.timeout) clearInterval(this.timeout); + } } diff --git a/src/drivers/dmx4all.ts b/src/drivers/dmx4all.ts index 8584af1..cc85e72 100644 --- a/src/drivers/dmx4all.ts +++ b/src/drivers/dmx4all.ts @@ -1,6 +1,4 @@ -import SerialPort from 'serialport'; -import {EventEmitter} from 'events'; -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; +import {AbstractSerialDriver} from './abstract-serial-driver'; const UNIVERSE_LEN = 512; @@ -8,37 +6,24 @@ export interface DMX4AllArgs { dmxSpeed?: number; } -export class DMX4AllDriver extends EventEmitter implements IUniverseDriver { - private readonly universe: Buffer; +export class DMX4AllDriver extends AbstractSerialDriver { private readyToWrite: boolean; - private readonly interval: number; - private readonly dev: SerialPort; - private intervalhandle?: any; - constructor(deviceId: string, options: DMX4AllArgs = {}) { - super(); - this.universe = Buffer.alloc(UNIVERSE_LEN + 1); - this.readyToWrite = true; - this.interval = 1000 / (options.dmxSpeed || 33); - this.dev = new SerialPort(deviceId, { - 'baudRate': 38400, - 'dataBits': 8, - 'stopBits': 1, - 'parity': 'none', - }, (err: any) => { - if (!err) { - this.start(); - } else { - console.warn(err); - } + constructor(serialPort: string, options: DMX4AllArgs = {}) { + super(serialPort, { + serialPortOptions: { + 'baudRate': 38400, + 'dataBits': 8, + 'stopBits': 1, + 'parity': 'none', + }, + sendInterval: 1000 / (options.dmxSpeed || 33), }); - // this.dev.on('data', data => { - // process.stdout.write(data.toString('ascii')) - // }); + this.readyToWrite = true; } - sendUniverse(): void { - if (!this.dev.writable) { + async sendUniverse(): Promise { + if (!this.serialPort.writable) { return; } @@ -50,51 +35,13 @@ export class DMX4AllDriver extends EventEmitter implements IUniverseDriver { for (let i = 0; i < UNIVERSE_LEN; i++) { msg[i * 3 + 0] = (i < 256) ? 0xE2 : 0xE3; msg[i * 3 + 1] = i; - msg[i * 3 + 2] = this.universe[i + 1]; + msg[i * 3 + 2] = this.universeBuffer[i + 1]; } - this.dev.write(msg); - this.dev.drain(() => { + this.serialPort.write(msg); + this.serialPort.drain(() => { this.readyToWrite = true; }); } } - - start(): void { - this.intervalhandle = setInterval(this.sendUniverse.bind(this), this.interval); - } - - stop(): void { - if (this.intervalhandle) clearInterval(this.intervalhandle); - } - - close(): Promise { - return new Promise((resolve, reject) => { - this.dev.close((e) => { - if (e) { - reject(e); - return; - } - resolve(); - }); - }); - } - - update(u: UniverseData, extraData?: any): void { - for (const c in u) { - this.universe[c] = u[c]; - } - - this.emit('update', u, extraData); - } - - updateAll(v: number): void { - for (let i = 1; i <= 512; i++) { - this.universe[i] = v; - } - } - - get(c: number): number { - return this.universe[c]; - } } diff --git a/src/drivers/dmxking-ultra-dmx-pro.ts b/src/drivers/dmxking-ultra-dmx-pro.ts index 17f4805..8cb64a2 100644 --- a/src/drivers/dmxking-ultra-dmx-pro.ts +++ b/src/drivers/dmxking-ultra-dmx-pro.ts @@ -1,6 +1,4 @@ -import SerialPort from 'serialport'; -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; -import { EventEmitter } from 'events'; +import {AbstractSerialDriver} from './abstract-serial-driver'; const DMXKING_ULTRA_DMX_PRO_DMX_STARTCODE = 0x00; const DMXKING_ULTRA_DMX_PRO_START_OF_MSG = 0x7e; @@ -8,6 +6,7 @@ const DMXKING_ULTRA_DMX_PRO_END_OF_MSG = 0xe7; const DMXKING_ULTRA_DMX_PRO_SEND_DMX_RQ = 0x06; const DMXKING_ULTRA_DMX_PRO_SEND_DMX_A_RQ = 0x64; const DMXKING_ULTRA_DMX_PRO_SEND_DMX_B_RQ = 0x65; + // var DMXKING_ULTRA_DMX_PRO_RECV_DMX_PKT = 0x05; export interface DMXKingUltraDMXProDriverArgs { @@ -15,106 +14,59 @@ export interface DMXKingUltraDMXProDriverArgs { port?: 'A' | 'B'; } -export class DMXKingUltraDMXProDriver extends EventEmitter implements IUniverseDriver { - options: DMXKingUltraDMXProDriverArgs; - universe: Buffer; - readyToWrite: boolean; - interval: number; - sendDMXReq: number; - dev: SerialPort; - intervalhandle?: any; - constructor(deviceId: string, options: DMXKingUltraDMXProDriverArgs = {}) { - super(); - this.options = options; - this.universe = Buffer.alloc(513, 0); - this.readyToWrite = true; - this.interval = 1000 / (options.dmxSpeed || 40); - - this.sendDMXReq = DMXKING_ULTRA_DMX_PRO_SEND_DMX_RQ; - if (this.options.port === 'A') { - this.sendDMXReq = DMXKING_ULTRA_DMX_PRO_SEND_DMX_A_RQ; - } else if (this.options.port === 'B') { - this.sendDMXReq = DMXKING_ULTRA_DMX_PRO_SEND_DMX_B_RQ; +export class DMXKingUltraDMXProDriver extends AbstractSerialDriver { + private readonly _options: DMXKingUltraDMXProDriverArgs; + private readonly _sendDMXReq: number; + private _readyToWrite: boolean; + + constructor(serialPort: string, options: DMXKingUltraDMXProDriverArgs = {}) { + super(serialPort, { + serialPortOptions: { + 'baudRate': 250000, + 'dataBits': 8, + 'stopBits': 2, + 'parity': 'none', + }, + sendInterval: 1000 / (options.dmxSpeed || 40), + }); + this._options = options; + this._readyToWrite = true; + + this._sendDMXReq = DMXKING_ULTRA_DMX_PRO_SEND_DMX_RQ; + if (this._options.port === 'A') { + this._sendDMXReq = DMXKING_ULTRA_DMX_PRO_SEND_DMX_A_RQ; + } else if (this._options.port === 'B') { + this._sendDMXReq = DMXKING_ULTRA_DMX_PRO_SEND_DMX_B_RQ; } - this.dev = new SerialPort(deviceId, { - 'baudRate': 250000, - 'dataBits': 8, - 'stopBits': 2, - 'parity': 'none', - }, (err) => { - if (!err) { - this.start(); - } else { - console.warn(err); - } - }); } - sendUniverse(): void { - if (!this.dev.writable) { + async sendUniverse(): Promise { + if (!this.serialPort.writable) { return; } - if (this.readyToWrite) { - this.readyToWrite = false; + if (this._readyToWrite) { + this._readyToWrite = false; const hdr = Buffer.from([ DMXKING_ULTRA_DMX_PRO_START_OF_MSG, - this.sendDMXReq, - (this.universe.length) & 0xff, - ((this.universe.length) >> 8) & 0xff, + this._sendDMXReq, + (this.universeBuffer.length) & 0xff, + ((this.universeBuffer.length) >> 8) & 0xff, DMXKING_ULTRA_DMX_PRO_DMX_STARTCODE, ]); const msg = Buffer.concat([ hdr, - this.universe.slice(1), + this.universeBuffer.slice(1), Buffer.from([DMXKING_ULTRA_DMX_PRO_END_OF_MSG]), ]); - this.dev.write(msg); - this.dev.drain(() => { - this.readyToWrite = true; + this.serialPort.write(msg); + this.serialPort.drain(() => { + this._readyToWrite = true; }); } } - - start(): void { - this.intervalhandle = setInterval(this.sendUniverse.bind(this), this.interval); - } - - stop(): void { - if (this.intervalhandle) clearInterval(this.intervalhandle); - } - - close(): Promise { - return new Promise((resolve, reject) => { - this.dev.close((e) => { - if (e) { - reject(e); - return; - } - resolve(); - }); - }); - } - - update(u: UniverseData, extraData?: any): void { - for (const c in u) { - this.universe[c] = u[c]; - } - - this.emit('update', u, extraData); - } - - updateAll(v: number): any { - for (let i = 1; i <= 512; i++) { - this.universe[i] = v; - } - } - - get(c: number): number { - return this.universe[c]; - } } diff --git a/src/drivers/enttec-open-usb-dmx.ts b/src/drivers/enttec-open-usb-dmx.ts index ef990c7..ab138ea 100644 --- a/src/drivers/enttec-open-usb-dmx.ts +++ b/src/drivers/enttec-open-usb-dmx.ts @@ -1,93 +1,53 @@ -import SerialPort from 'serialport'; -import {IUniverseDriver} from '../models/IUniverseDriver'; -import {EventEmitter} from 'events'; +import {wait} from '../util/time'; +import {AbstractSerialDriver} from './abstract-serial-driver'; export interface EnttecOpenUsbDmxArgs { dmxSpeed?: number; } -export class EnttecOpenUSBDMXDriver extends EventEmitter implements IUniverseDriver { - private readonly _universe: Buffer; - private readonly _interval: number; - private readonly _dev: SerialPort; - +/** + * Controls the Enttec Open DMX device: + * https://www.enttec.com.au/product/lighting-communication-protocols/usb-lighting-interface/open-dmx-usb/ + * + * The controller uses a FTDI FT232RL chip for serial communication. See + * [here](http://www.ftdichip.com/Support/Documents/ProgramGuides/D2XX_Programmer's_Guide(FT_000071).pdf) + * for an API reference and to translate the Enttec code examples to Node.js/Serialport. + */ +export class EnttecOpenUSBDMXDriver extends AbstractSerialDriver { private _readyToWrite: boolean; - private _intervalHandle?: any; - - constructor(deviceId: string, args: EnttecOpenUsbDmxArgs) { - super(); - - this._universe = Buffer.alloc(513); - this._readyToWrite = true; - this._interval = args?.dmxSpeed ? (1000 / args.dmxSpeed) : 46; - this._dev = new SerialPort(deviceId, { - 'baudRate': 250000, - 'dataBits': 8, - 'stopBits': 2, - 'parity': 'none', - }, (err: any) => { - if (!err) { - this.start(); - } else { - console.warn(err); - } + constructor(serialPort: string, args?: EnttecOpenUsbDmxArgs) { + super(serialPort, { + serialPortOptions: { + 'baudRate': 250000, + 'dataBits': 8, + 'stopBits': 2, + 'parity': 'none', + }, + sendInterval: args?.dmxSpeed ? (1000 / args.dmxSpeed) : 46, }); - } - update(channels: {[key: number]: number}, extraData?: any): void { - for (const c in channels) { - this._universe[c] = channels[c]; - } - - this.emit('update', channels, extraData); - } - - updateAll(value: any): void { - for (let i = 1; i <= 512; i++) { - this._universe[i] = value; - } + this._readyToWrite = true; } - sendUniverse(): void { - const self = this; - - if (!this._dev.writable) { + async sendUniverse(): Promise { + if (!this.serialPort.writable) { return; } // toggle break - self._dev.set({brk: true, rts: true}, (err: any) => { - setTimeout(() => { - self._dev.set({brk: false, rts: true}, (err: any) => { - setTimeout(() => { - if (self._readyToWrite) { - self._readyToWrite = false; - self._dev.write(Buffer.concat([Buffer.from([0]), self._universe.slice(1)])); - self._dev.drain(() => { - self._readyToWrite = true; - }); - } - }, 1); - }); - }, 1); - }); - } - - start(): void { - this._intervalHandle = setInterval(this.sendUniverse.bind(this), this._interval); - } - - stop(): void { - this._intervalHandle && clearInterval(this._intervalHandle); - } - - close(): Promise { - this.stop(); - return new Promise((resolve, reject) => this._dev.close((err: any)=>err ? reject(err) : resolve(err))); - } - - get(c: number): number { - return this._universe[c]; + await this.serialPort.set({brk: true, rts: false}); + await wait(1); + await this.serialPort.set({brk: false, rts: false}); + await wait(1); + if (this._readyToWrite) { + const dataToWrite = Buffer.concat([Buffer.from([0]), this.universeBuffer.slice(1)]); + + this._readyToWrite = false; + this.serialPort.write(dataToWrite); + this.serialPort.drain(() => { + this._readyToWrite = true; + }); + } } } diff --git a/src/drivers/enttec-usb-dmx-pro.ts b/src/drivers/enttec-usb-dmx-pro.ts index 2d60815..78177d9 100644 --- a/src/drivers/enttec-usb-dmx-pro.ts +++ b/src/drivers/enttec-usb-dmx-pro.ts @@ -1,106 +1,58 @@ -import SerialPort from 'serialport'; -import { EventEmitter } from 'events'; -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; +import {AbstractSerialDriver} from './abstract-serial-driver'; const ENTTEC_PRO_DMX_STARTCODE = 0x00; const ENTTEC_PRO_START_OF_MSG = 0x7e; const ENTTEC_PRO_END_OF_MSG = 0xe7; const ENTTEC_PRO_SEND_DMX_RQ = 0x06; + // var ENTTEC_PRO_RECV_DMX_PKT = 0x05; export interface EnttecUSBDMXProArgs { dmxSpeed?: number; } -export class EnttecUSBDMXProDriver extends EventEmitter implements IUniverseDriver { - universe: Buffer; - readyToWrite: boolean; - interval: number; - dev: SerialPort; - intervalhandle?: any; - constructor(deviceId: string, options: EnttecUSBDMXProArgs = {}) { - super(); - this.universe = Buffer.alloc(513, 0); - this.readyToWrite = true; - this.interval = 1000 / (options.dmxSpeed || 40); - - this.dev = new SerialPort(deviceId, { - 'baudRate': 250000, - 'dataBits': 8, - 'stopBits': 2, - 'parity': 'none', - }, err => { - if (!err) { - this.start(); - } else { - console.warn(err); - } +export class EnttecUSBDMXProDriver extends AbstractSerialDriver { + private _readyToWrite: boolean; + + constructor(serialPort: string, options: EnttecUSBDMXProArgs = {}) { + super(serialPort, { + serialPortOptions: { + 'baudRate': 250000, + 'dataBits': 8, + 'stopBits': 2, + 'parity': 'none', + }, + sendInterval: 1000 / (options.dmxSpeed || 40), }); + + this._readyToWrite = true; } - sendUniverse(): void { - if (!this.dev.writable) { + async sendUniverse(): Promise { + if (!this.serialPort.writable) { return; } - if (this.readyToWrite) { + if (this._readyToWrite) { const hdr = Buffer.from([ ENTTEC_PRO_START_OF_MSG, ENTTEC_PRO_SEND_DMX_RQ, - (this.universe.length) & 0xff, - ((this.universe.length) >> 8) & 0xff, + (this.universeBuffer.length) & 0xff, + ((this.universeBuffer.length) >> 8) & 0xff, ENTTEC_PRO_DMX_STARTCODE, ]); const msg = Buffer.concat([ hdr, - this.universe.slice(1), + this.universeBuffer.slice(1), Buffer.from([ENTTEC_PRO_END_OF_MSG]), ]); - this.readyToWrite = false; - this.dev.write(msg); - this.dev.drain(() => { - this.readyToWrite = true; - }); - } - } - - start(): void { - this.intervalhandle = setInterval(this.sendUniverse.bind(this), this.interval); - } - - stop(): void { - if (this.intervalhandle) clearInterval(this.intervalhandle); - } - - close(): Promise { - return new Promise((resolve, reject) => { - this.dev.close((e) => { - if (e) { - reject(e); - return; - } - resolve(); + this._readyToWrite = false; + this.serialPort.write(msg); + this.serialPort.drain(() => { + this._readyToWrite = true; }); - }); - } - - update(u: UniverseData, extraData?: any): void { - for (const c in u) { - this.universe[c] = u[c]; - } - - this.emit('update', u, extraData); - } - - updateAll(v: number): void { - for (let i = 1; i <= 512; i++) { - this.universe[i] = v; } } - - get(c: number): number { - return this.universe[c]; - } } diff --git a/src/drivers/null.ts b/src/drivers/null.ts index 2c03a58..3da5dd4 100644 --- a/src/drivers/null.ts +++ b/src/drivers/null.ts @@ -11,21 +11,16 @@ export class NullDriver extends EventEmitter implements IUniverseDriver { this._universe = Buffer.alloc(513, 0); this._interval = 1000 / (options?.dmxSpeed ?? 1); - this.start(); } - start(): void { - this._timeout = setInterval(() => { - this.logUniverse(); - }, this._interval); + async init(): Promise { + this.start(); } - stop(): void { - clearInterval(this._timeout); + close(): void { + this.stop(); } - close(): void {} - update(u: {[key: number]: number}, extraData: any): void { for (const c in u) { this._universe[c] = u[c]; @@ -49,6 +44,16 @@ export class NullDriver extends EventEmitter implements IUniverseDriver { console.log(this._universe.slice(1)); } + private start(): void { + this._timeout = setInterval(() => { + this.logUniverse(); + }, this._interval); + } + + private stop(): void { + clearInterval(this._timeout); + } + private readonly _universe: Buffer; private readonly _interval: number; private _timeout: any; diff --git a/src/drivers/sacn.ts b/src/drivers/sacn.ts index fa76efa..28027a2 100644 --- a/src/drivers/sacn.ts +++ b/src/drivers/sacn.ts @@ -1,10 +1,11 @@ -import { EventEmitter } from 'events'; -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; +import {EventEmitter} from 'events'; +import {IUniverseDriver, UniverseData} from '../models/IUniverseDriver'; import * as sacn from 'sacn'; export class SACNDriver extends EventEmitter implements IUniverseDriver { sACNServer: any; universe: any = {}; + constructor(universe = 1) { super(); this.sACNServer = new sacn.Sender({ @@ -13,19 +14,16 @@ export class SACNDriver extends EventEmitter implements IUniverseDriver { }); } - start(): void {} - - stop(): void { - this.sACNServer.close(); + async init(): Promise { } close(): void { - this.stop(); + this.sACNServer.close(); } update(u: UniverseData, extraData: any): void { for (const c in u) { - this.universe[c] = this.dmxToPercent(u[c]); + this.universe[c] = SACNDriver.dmxToPercent(u[c]); } this.sendUniverse(); } @@ -38,20 +36,20 @@ export class SACNDriver extends EventEmitter implements IUniverseDriver { updateAll(v: number): void { for (let i = 1; i <= 512; i++) { - this.universe[i] = this.dmxToPercent(v); + this.universe[i] = SACNDriver.dmxToPercent(v); } this.sendUniverse(); } get(c: number): number { - return this.percentToDmx(this.universe[c]); + return SACNDriver.percentToDmx(this.universe[c]); } - dmxToPercent(v: number): number { + static dmxToPercent(v: number): number { return v / 255 * 100; } - percentToDmx(v: number): number { + static percentToDmx(v: number): number { return v / 100 * 255; } } diff --git a/src/drivers/socketio.ts b/src/drivers/socketio.ts index 2cf66d7..bbfd887 100644 --- a/src/drivers/socketio.ts +++ b/src/drivers/socketio.ts @@ -1,6 +1,6 @@ -import { IUniverseDriver, UniverseData } from '../models/IUniverseDriver'; +import {IUniverseDriver, UniverseData} from '../models/IUniverseDriver'; import * as io from 'socket.io'; -import { EventEmitter } from 'events'; +import {EventEmitter} from 'events'; export interface SocketIOArgs { port?: number; @@ -10,11 +10,11 @@ export interface SocketIOArgs { export class SocketIODriver extends EventEmitter implements IUniverseDriver { universe: Buffer; server: io.Server; + constructor(options: SocketIOArgs) { super(); options = options || {}; - const self = this; const port = options.port || 18909; const debug = options.debug || false; @@ -27,14 +27,13 @@ export class SocketIODriver extends EventEmitter implements IUniverseDriver { }); this.universe = Buffer.alloc(513, 0); - self.start(); } - start(): void { } - - stop(): void {} + async init(): Promise { + } - close(): void {} + close(): void { + } update(u: UniverseData, extraData: any): void { for (const c in u) { diff --git a/src/models/IUniverseDriver.ts b/src/models/IUniverseDriver.ts index 97c8ab5..66519ca 100644 --- a/src/models/IUniverseDriver.ts +++ b/src/models/IUniverseDriver.ts @@ -1,17 +1,16 @@ import { EventEmitter } from 'events'; export type UniverseData = { - [channel: number]: number; + [key: number]: number; } export interface IUniverseDriver extends EventEmitter { + init(): Promise; update(channels: UniverseData, extraData?: any): void; - get(c: number): number; + get(channel: number): number; updateAll(value: number): void; - start(): Promise | void; - stop(): Promise | void; close(): Promise | void; } diff --git a/src/util/time.ts b/src/util/time.ts new file mode 100644 index 0000000..a90656a --- /dev/null +++ b/src/util/time.ts @@ -0,0 +1 @@ +export const wait = ( millis: number ): Promise => new Promise( ( resolve ) => setTimeout( resolve, millis ) );