added USBDMX In -> Artnet Out

This commit is contained in:
Adrian Baumgart 2024-05-08 18:34:10 +02:00
parent 876dc890e5
commit 52ff5d9d90
No known key found for this signature in database
5 changed files with 88 additions and 32 deletions

View File

@ -1,8 +1,8 @@
name: Build app name: Build app
on: #on:
push: # push:
branches: # branches:
- main # - main
jobs: jobs:
build: build:

View File

@ -1,4 +1,4 @@
import {dmxnet, receiver} from "dmxnet"; import {dmxnet, receiver, sender} from "dmxnet";
import {DetectedInterface, DMXInterface, getConnectedInterfaces} from "./usbdmx"; import {DetectedInterface, DMXInterface, getConnectedInterfaces} from "./usbdmx";
import {clearInterval} from "timers"; import {clearInterval} from "timers";
@ -8,6 +8,7 @@ import {clearInterval} from "timers";
export default class ConvertHandler { export default class ConvertHandler {
dmxnetManager: dmxnet; dmxnetManager: dmxnet;
artNetReceiver: receiver; artNetReceiver: receiver;
artNetSender: sender;
recentDMXArray: number[] = Array(512).fill(0); recentDMXArray: number[] = Array(512).fill(0);
@ -16,39 +17,71 @@ export default class ConvertHandler {
dmxInterface: DMXInterface | undefined; dmxInterface: DMXInterface | undefined;
outputAllowed = false; outputAllowed = false;
incomingDataCounter = 0;
sentDataCounter = 0;
dataPerSecTimer: NodeJS.Timeout; dataPerSecTimer: NodeJS.Timeout;
incomingDataHistory: number[] = [];
sentDataHistory: number[] = []; private artnetInCounter = 0;
private artnetOutCounter = 0;
private usbdmxInCounter = 0;
private usbdmxOutCounter = 0;
artnetInCountHistory: number[] = [];
artnetOutCountHistory: number[] = [];
usbdmxInCountHistory: number[] = [];
usbdmxOutCountHistory: number[] = [];
/** /**
* Starts up the Art-Net receiver * Starts up the Art-Net receiver
*/ */
startArtNetReceiver = () => { startArtNetReceiver = () => {
this.dmxnetManager = new dmxnet({ this.dmxnetManager = new dmxnet({
log: {level: "error"} log: {level: "error"},
sName: "usbdmx",
lName: "ArtNet-USBDMX-Converter",
}); });
this.artNetReceiver = this.dmxnetManager.newReceiver(); this.artNetReceiver = this.dmxnetManager.newReceiver();
this.artNetSender = this.dmxnetManager.newSender({
ip: "255.255.255.255", //IP to send to, default 255.255.255.255
subnet: 0, //Destination subnet, default 0
universe: 0, //Destination universe, default 0
net: 0, //Destination net, default 0
port: 6454, //Destination UDP Port, default 6454
base_refresh_interval: 1000 // Default interval for sending unchanged ArtDmx
});
this.artNetReceiver.on("data", this.handleIncomingArtNetData); this.artNetReceiver.on("data", this.handleIncomingArtNetData);
} }
/** /**
* Handles incoming Art-Net dara and writes it to the DMX interface * Handles incoming Art-Net dara and writes it to the DMX interface.
* @param data Art-Net data * @param data Art-Net data
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
handleIncomingArtNetData = (data: any) => { handleIncomingArtNetData = (data: any) => {
this.incomingDataCounter++; this.artnetInCounter++;
if (JSON.stringify(data) != JSON.stringify(this.recentDMXArray)) { if (JSON.stringify(data) != JSON.stringify(this.recentDMXArray)) {
if (this.dmxInterface && this.outputAllowed) { if (this.dmxInterface && this.outputAllowed) {
this.sentDataCounter++; this.usbdmxOutCounter++;
this.dmxInterface.writeMap(data); this.dmxInterface.writeMap(data);
} }
this.recentDMXArray = data; this.recentDMXArray = data;
} }
} }
/**
* Handles incoming data from the interface and sends it out via Art-Net.
* @param startChannel first channel number of the data array
* @param data Array with dmx values
*/
sendIncomingUSBDMXData = (startChannel: number, data: number[]) => {
this.usbdmxInCounter++;
if (this.outputAllowed) {
for (let i = 0; i < data.length; i++) {
this.artNetSender.prepChannel(startChannel + i, data[i]);
}
this.artnetOutCounter++;
this.artNetSender.transmit();
}
}
/** /**
* Gets available DMX interfaces connected to the computer * Gets available DMX interfaces connected to the computer
*/ */
@ -75,6 +108,7 @@ export default class ConvertHandler {
try { try {
this.dmxInterface = await DMXInterface.open(interfacePath, serial, manufacturer, product); this.dmxInterface = await DMXInterface.open(interfacePath, serial, manufacturer, product);
this.dmxInterface.usbdmxInputCallback = this.sendIncomingUSBDMXData;
return new Promise<string>((resolve) => { return new Promise<string>((resolve) => {
setTimeout( () => { setTimeout( () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -108,16 +142,29 @@ export default class ConvertHandler {
* Processes incoming and sent data history for visualization * Processes incoming and sent data history for visualization
*/ */
parseRequestTimer = () => { parseRequestTimer = () => {
this.incomingDataHistory.push(this.incomingDataCounter); this.artnetInCountHistory.push(this.artnetInCounter);
if (this.incomingDataHistory.length > 20) { if (this.artnetInCountHistory.length > 20) {
this.incomingDataHistory = this.incomingDataHistory.slice(1) this.artnetInCountHistory = this.artnetInCountHistory.slice(1)
} }
this.sentDataHistory.push(this.sentDataCounter); this.artnetOutCountHistory.push(this.artnetOutCounter);
if (this.sentDataHistory.length > 20) { if (this.artnetOutCountHistory.length > 20) {
this.sentDataHistory = this.sentDataHistory.slice(1) this.artnetOutCountHistory = this.artnetOutCountHistory.slice(1)
} }
this.incomingDataCounter = 0;
this.sentDataCounter = 0; this.usbdmxInCountHistory.push(this.usbdmxInCounter);
if (this.usbdmxInCountHistory.length > 20) {
this.usbdmxInCountHistory = this.usbdmxInCountHistory.slice(1)
}
this.usbdmxOutCountHistory.push(this.usbdmxOutCounter);
if (this.usbdmxOutCountHistory.length > 20) {
this.usbdmxOutCountHistory = this.usbdmxOutCountHistory.slice(1)
}
this.artnetInCounter = 0;
this.artnetOutCounter = 0;
this.usbdmxInCounter = 0;
this.usbdmxOutCounter = 0;
} }
} }

View File

@ -36,13 +36,19 @@ export default async function renderControlScreen() {
`${modeToString(defaultConvertHandler.dmxInterface?.currentMode ?? 0)}`) `${modeToString(defaultConvertHandler.dmxInterface?.currentMode ?? 0)}`)
console.log("=================") console.log("=================")
const incomingDataSparkline = Sparkline(defaultConvertHandler.incomingDataHistory, "req/sec"); const artnetInSparkline = Sparkline(defaultConvertHandler.artnetInCountHistory, "req/sec");
const sentDataSparkline = Sparkline(defaultConvertHandler.sentDataHistory, "req/sec"); const artnetOutSparkline = Sparkline(defaultConvertHandler.artnetOutCountHistory, "req/sec");
const usbdmxInSparkline = Sparkline(defaultConvertHandler.usbdmxInCountHistory, "req/sec");
const usbdmxOutSparkline = Sparkline(defaultConvertHandler.usbdmxOutCountHistory, "req/sec");
process.stdout.write("Incoming Data ") process.stdout.write("ArtNet In\t")
process.stdout.write(incomingDataSparkline); process.stdout.write(artnetInSparkline);
process.stdout.write("\nOutgoing Data ") process.stdout.write("\nArtNet Out\t")
process.stdout.write(sentDataSparkline); process.stdout.write(artnetOutSparkline);
process.stdout.write("\nUSBDMX In\t")
process.stdout.write(usbdmxInSparkline);
process.stdout.write("\nUSBDMX Out\t")
process.stdout.write(usbdmxOutSparkline);
console.log("\n"); console.log("\n");
console.log(chalk.yellow( console.log(chalk.yellow(

View File

@ -18,7 +18,7 @@ async function main() {
"Starting ArtNet..." "Starting ArtNet..."
)); ));
console.log(chalk.yellow( console.log(chalk.yellow(
"Nimm bitte eventuell erscheinende Firewall-Hinweise an" "Please accept any firewall requests"
)) ))
defaultConvertHandler.startArtNetReceiver(); defaultConvertHandler.startArtNetReceiver();
@ -42,7 +42,7 @@ async function main() {
); );
renderControlScreenTimer = setInterval(() => { renderControlScreenTimer = setInterval(() => {
renderControlScreen(); renderControlScreen();
}, 1000); }, 1000)
} }
} }

View File

@ -22,7 +22,8 @@ class DMXInterface {
currentMode = 0; currentMode = 0;
hidDevice: HID.HID; hidDevice: HID.HID;
dmxout: number[]; dmxout: number[];
dataCallback: (value: DMXCommand) => void;
usbdmxInputCallback: (start: number, values: number[]) => void;
constructor( constructor(
path: string, path: string,
@ -35,14 +36,16 @@ class DMXInterface {
this.manufacturer = manufacturer; this.manufacturer = manufacturer;
this.product = product; this.product = product;
this.dataCallback = () => {};
this.hidDevice = new HID.HID(path); this.hidDevice = new HID.HID(path);
this.hidDevice.on("data", (data: Buffer) => { this.hidDevice.on("data", (data: Buffer) => {
// received buffer contains 33 bytes, the first one (data[0]) is the page and the rest are the dmx channel values // received buffer contains 33 bytes, the first one (data[0]) is the page and the rest are the dmx channel values
// this means we get 32 dmx channels in one package // this means we get 32 dmx channels in one package
const values: number[] = [];
for (let i = 1; i < 33; i++) { for (let i = 1; i < 33; i++) {
this.dataCallback({channel: data[0] * 32 + i, value: data[i]}); values.push(data[i]);
} }
this.usbdmxInputCallback(data[0] * 32, values);
}) })
this.dmxout = Array(512).fill(0); this.dmxout = Array(512).fill(0);