Remove library and demo usage code. Updated readme.

This commit is contained in:
Frédéric Bolvin 2018-12-29 21:59:48 +00:00
parent cc7210111e
commit e67d91c5e3
16 changed files with 34 additions and 1062 deletions

83
anim.js
View file

@ -1,83 +0,0 @@
const ease = require('./easing.js').ease;
const resolution = 25;
class Anim {
constructor() {
this.fxStack = [];
this.interval = null;
}
add(to, duration = resolution, options = {}) {
options.easing = options.easing || 'linear';
this.fxStack.push({ 'to': to, 'duration': duration, 'options': options });
return this;
}
delay(duration) {
this.add({}, duration);
return this;
}
stop() {
if (this.interval) {
clearInterval(this.interval);
}
this.fxStack = [];
}
run(universe, onFinish) {
let config = {};
let ticks = 0;
let duration = 0;
let animationStep;
let iid = null;
const stack = [ ...this.fxStack ];
const aniSetup = () => {
animationStep = stack.shift();
ticks = 0;
duration = animationStep.duration;
config = {};
for (const k in animationStep.to) {
config[k] = {
'start': universe.get(k),
'end': animationStep.to[k],
'options': animationStep.options,
};
}
};
const aniStep = () => {
const newValues = {};
for (const k in config) {
const entry = config[k];
const easing = ease[entry.options.easing];
newValues[k] = Math.round(entry.start + easing(ticks, 0, 1, duration) * (entry.end - entry.start));
}
ticks = ticks + resolution;
universe.update(newValues);
if (ticks > duration) {
if (stack.length > 0) {
aniSetup();
} else {
clearInterval(iid);
if (onFinish) {
onFinish();
}
}
}
};
aniSetup();
iid = this.interval = setInterval(aniStep, resolution);
return this;
}
}
module.exports = Anim;

84
demo.js
View file

@ -1,84 +0,0 @@
const DMX = require('./dmx');
const dmx = new DMX();
const A = dmx.animation;
// 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', 'null');
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 done() {console.log('DONE');}
function greenWater(universe, channels, duration) {
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 = {};
for (let i = 0; i < 3; i++) {
u[channels[c] + i] = colors[r][i];
}
new A().add(u, duration).run(universe);
}
setTimeout(function () {greenWater(universe, channels, duration);}, duration * 2);
}
function warp(universe, channel, min, max, duration) {
const a = {}, b = {};
a[channel] = min;
b[channel] = max;
new A().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);
return;
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});
const y = new A()
.add({9: 255}, 10000);
x.run(universe, done);
y.run(universe, done);

View file

@ -1,20 +0,0 @@
const DMX = require('./dmx');
const dmx = new DMX();
// var universe = dmx.addUniverse('demo', 'enttec-open-usb-dmx', '/dev/cu.usbserial-6AVNHXS8')
const universe = dmx.addUniverse('demo', 'null');
let on = false;
setInterval(() => {
if (on) {
on = false;
universe.updateAll(0);
console.log('off');
} else {
on = true;
universe.updateAll(250);
console.log('on');
}
}, 1000);

View file

@ -1,129 +0,0 @@
module.exports = {
'generic': {
channels: ['dimmer'],
},
'generic-rgb': {
channels: ['red', 'green', 'blue'],
},
'showtec-multidim2': {
channels: ['1', '2', '3', '4'],
},
'eurolite-led-bar': {
channels: [
'ctrl',
'dimmer',
'strobe',
'red0',
'green0',
'blue0',
'red1',
'green1',
'blue1',
'red2',
'green2',
'blue2',
],
ranges: {
'ctrl': {
'type': 'option',
'options': [
{ 'value': 0, 'label': 'Black Out' },
{ 'value': 1, 'label': 'Dimmer 1' },
{ 'value': 16, 'label': 'Dimmer 2' },
{ 'value': 32, 'label': 'Red' },
{ 'value': 48, 'label': 'Green' },
{ 'value': 64, 'label': 'Blue' },
{ 'value': 80, 'label': 'Purple' },
{ 'value': 96, 'label': 'Yellow' },
{ 'value': 112, 'label': 'Cyan' },
{ 'value': 128, 'label': 'White' },
{ 'value': 144, 'label': 'Color change' },
{ 'value': 160, 'label': 'Color flow' },
{ 'value': 176, 'label': 'Color dream' },
{ 'value': 192, 'label': 'Multi flow' },
{ 'value': 208, 'label': 'Dream flow' },
{ 'value': 224, 'label': 'Two color flow' },
{ 'value': 240, 'label': 'Sound activity' },
],
},
'dimmer': {
'type': 'slider',
'min': 0,
'max': 255,
},
},
},
'stairville-led-par-56': {
channels: ['ctrl', 'red', 'green', 'blue', 'speed'],
ranges: {
'ctrl': {
'type': 'option',
'options': [
{ 'value': 0, 'label': 'RGB Control' },
{ 'value': 64, 'label': '7 color fade' },
{ 'value': 128, 'label': '7 color change' },
{ 'value': 192, 'label': '3 color change' },
],
},
},
},
'ultra-pro-24ch-rdm': {
channels: [...Array(25).keys()].slice(1),
},
'ultra-pro-6rgbch-rdm': {
channels: [...Array(25).keys()].slice(1),
channelgroups: ['1', '2', '3', '4', '5', '6'],
},
'oppsk-cob-uv-par': {
channels: ['dimmer', 'strobe', 'program-speed', 'sound-activity'],
},
'lixda-par12-led': {
channels: ['ctrl', 'static-color', 'speed', 'dimmer', 'red', 'green', 'blue', 'white'],
ranges: {
'ctrl': {
'type': 'option',
'options': [
{ 'value': 0, 'label': 'Off' },
{ 'value': 11, 'label': 'Static Color' },
{ 'value': 51, 'label': 'Jump' },
{ 'value': 101, 'label': 'Gradual' },
{ 'value': 151, 'label': 'Sound Activate' },
{ 'value': 200, 'label': 'Strobe' },
],
},
'static-color': {
'type': 'option',
'options': [
{ 'value': 0, 'label': 'All Color' },
{ 'value': 40, 'label': 'Red' },
{ 'value': 50, 'label': 'Green' },
{ 'value': 60, 'label': 'Blue' },
{ 'value': 70, 'label': 'Yellow' },
{ 'value': 80, 'label': 'Cyan' },
{ 'value': 90, 'label': 'Purple' },
{ 'value': 100, 'label': 'White' },
{ 'value': 110, 'label': 'Red + Green' },
{ 'value': 120, 'label': 'Red + Blue' },
{ 'value': 130, 'label': 'Red + White' },
{ 'value': 140, 'label': 'Green + Blue' },
{ 'value': 150, 'label': 'Green + White' },
{ 'value': 160, 'label': 'Blue + White' },
{ 'value': 170, 'label': 'Red + Green + White' },
{ 'value': 180, 'label': 'Red + Blue + White' },
{ 'value': 190, 'label': 'Green + Blue + White' },
{ 'value': 200, 'label': 'Red + Green + Blue' },
{ 'value': 210, 'label': 'Red + Green + Blue + White' },
],
},
},
},
'eurolite-led-tha-120PC': {
channels: ['red', 'green', 'blue', 'white', 'dimmer', 'strobe', 'effect'],
},
'briteq-bt-theatre-60FC': {
channels: ['dimmer', 'strobe', 'effect', 'red', 'green', 'blue', 'white'],
},
'lalucenatz-led-4ch': {
channels: ['master', 'red', 'green', 'blue'],
},
};

View file

@ -5,7 +5,7 @@ const body = require('body-parser');
const express = require('express'); const express = require('express');
const socketio = require('socket.io'); const socketio = require('socket.io');
const program = require('commander'); const program = require('commander');
const DMX = require('./dmx'); const DMX = require('@node-dmx/dmx-library');
const A = DMX.Animation; const A = DMX.Animation;
program program

58
dmx.js
View file

@ -1,58 +0,0 @@
const util = require('util');
const EventEmitter = require('events').EventEmitter;
class DMX {
constructor(options) {
const opt = options || {};
const devices = opt.devices || {};
this.universes = {};
this.drivers = {};
this.devices = Object.assign({}, require('./devices'), devices);
this.animation = require('./anim');
this.registerDriver('null', require('./drivers/null'));
this.registerDriver('dmx4all', require('./drivers/dmx4all'));
this.registerDriver('enttec-usb-dmx-pro', require('./drivers/enttec-usb-dmx-pro'));
this.registerDriver('enttec-open-usb-dmx', require('./drivers/enttec-open-usb-dmx'));
this.registerDriver('dmxking-ultra-dmx-pro', require('./drivers/dmxking-ultra-dmx-pro'));
this.registerDriver('artnet', require('./drivers/artnet'));
this.registerDriver('bbdmx', require('./drivers/bbdmx'));
}
registerDriver(name, module) {
this.drivers[name] = module;
}
addUniverse(name, driver, deviceId, options) {
this.universes[name] = new this.drivers[driver](deviceId, options);
return this.universes[name];
}
update(universe, channels) {
this.universes[universe].update(channels);
this.emit('update', universe, channels);
}
updateAll(universe, value) {
this.universes[universe].updateAll(value);
this.emit('updateAll', universe, value);
}
universeToObject(universeKey) {
const universe = this.universes[universeKey];
const u = {};
for (let i = 0; i < 512; i++) {
u[i] = universe.get(i);
}
return u;
}
}
util.inherits(DMX, EventEmitter);
DMX.devices = require('./devices');
DMX.Animation = require('./anim');
module.exports = DMX;

View file

@ -1,67 +0,0 @@
const dgram = require('dgram');
function EnttecODE(deviceId = '127.0.0.1', options = {}) {
const self = this;
self.header = new Buffer([65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14]);
self.sequence = new Buffer([0]);
self.physical = new Buffer([0]);
self.universeId = new Buffer([0x00, 0x00]);
self.length = new Buffer([0x02, 0x00]);
self.universe = new Buffer(513);
self.universe.fill(0);
self.sleepTime = 24;
self.universe_id.writeInt16LE(options.universe || 0, 0);
self.host = deviceId;
self.port = options.port || 6454;
self.dev = dgram.createSocket('udp4');
self.dev.bind(() => self.dev.setBroadcast(true));
self.start();
}
EnttecODE.prototype.sendUniverse = function () {
const pkg = Buffer.concat([
this.header,
this.sequence,
this.physical,
this.universe_id,
this.length,
this.universe.slice(1),
]);
this.dev.send(pkg, 0, pkg.length, this.port, this.host);
};
EnttecODE.prototype.start = function () {
this.timeout = setInterval(this.sendUniverse.bind(this), this.sleepTime);
};
EnttecODE.prototype.stop = function () {
clearInterval(this.timeout);
};
EnttecODE.prototype.close = function (cb) {
this.stop();
cb(null);
};
EnttecODE.prototype.update = function (u) {
for (const c in u) {
this.universe[c] = u[c];
}
};
EnttecODE.prototype.updateAll = function (v) {
for (const i = 1; i <= 512; i++) {
this.universe[i] = v;
}
};
EnttecODE.prototype.get = function (c) {
return this.universe[c];
};
module.exports = EnttecODE;

View file

@ -1,58 +0,0 @@
const dgram = require('dgram');
const UNIVERSE_LEN = 512;
function BBDMX(deviceId = '127.0.0.1', options = {}) {
const self = this;
self.options = options;
self.universe = new Buffer(UNIVERSE_LEN + 1);
self.universe.fill(0);
self.host = deviceId;
self.port = self.options.port || 9930;
self.dev = dgram.createSocket('udp4');
self.sleepTime = 24;
self.start();
}
BBDMX.prototype.sendUniverse = function () {
let channel;
let messageBuffer = new Buffer(UNIVERSE_LEN.toString());
for (const i = 1; i <= UNIVERSE_LEN; i++) {
channel = new Buffer(' ' + this.universe[i]);
messageBuffer = Buffer.concat([messageBuffer, channel]);
}
this.dev.send(messageBuffer, 0, messageBuffer.length, this.port, this.host);
};
BBDMX.prototype.start = function () {
this.timeout = setInterval(this.sendUniverse.bind(this), this.sleepTime);
};
BBDMX.prototype.stop = function () {
clearInterval(this.timeout);
};
BBDMX.prototype.close = function (cb) {
this.stop();
cb(null);
};
BBDMX.prototype.update = function (u) {
for (const c in u) {
this.universe[c] = u[c];
}
};
BBDMX.prototype.updateAll = function (v) {
for (const i = 1; i <= UNIVERSE_LEN; i++) {
this.universe[i] = v;
}
};
BBDMX.prototype.get = function (c) {
return this.universe[c];
};
module.exports = BBDMX;

View file

@ -1,66 +0,0 @@
const SerialPort = require('serialport');
const UNIVERSE_LEN = 512;
function DMX4ALL(deviceId, options = {}) {
const self = this;
this.universe = new Buffer(UNIVERSE_LEN + 1);
this.universe.fill(0);
this.dev = new SerialPort(deviceId, {
'baudRate': 38400,
'dataBits': 8,
'stopBits': 1,
'parity': 'none',
}, err => {
if (!err) {
self.sendUniverse();
}
});
this.dev.on('data', data => {
// process.stdout.write(data.toString('ascii'))
});
}
DMX4ALL.prototype.sendUniverse = function () {
if (!this.dev.writable) {
return;
}
const msg = Buffer(UNIVERSE_LEN * 3);
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];
}
this.dev.write(msg);
};
DMX4ALL.prototype.start = () => {};
DMX4ALL.prototype.stop = () => {};
DMX4ALL.prototype.close = function (cb) {
this.dev.close(cb);
};
DMX4ALL.prototype.update = function (u) {
for (const c in u) {
this.universe[c] = u[c];
}
this.sendUniverse();
};
DMX4ALL.prototype.updateAll = function (v) {
for (let i = 1; i <= 512; i++) {
this.universe[i] = v;
}
this.sendUniverse();
};
DMX4ALL.prototype.get = function (c) {
return this.universe[c];
};
module.exports = DMX4ALL;

View file

@ -1,82 +0,0 @@
const SerialPort = require('serialport');
const DMXKING_ULTRA_DMX_PRO_DMX_STARTCODE = 0x00;
const DMXKING_ULTRA_DMX_PRO_START_OF_MSG = 0x7e;
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;
function DMXKingUltraDMXPro(deviceId, options = {}) {
const self = this;
this.options = options;
this.universe = Buffer.alloc(513, 0);
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) {
self.sendUniverse();
}
});
}
DMXKingUltraDMXPro.prototype.sendUniverse = function () {
if (!this.dev.writable) {
return;
}
const hdr = Buffer.from([
DMXKING_ULTRA_DMX_PRO_START_OF_MSG,
this.sendDMXReq,
(this.universe.length) & 0xff,
((this.universe.length) >> 8) & 0xff,
DMXKING_ULTRA_DMX_PRO_DMX_STARTCODE,
]);
const msg = Buffer.concat([
hdr,
this.universe.slice(1),
Buffer.from([DMXKING_ULTRA_DMX_PRO_END_OF_MSG]),
]);
this.dev.write(msg);
};
DMXKingUltraDMXPro.prototype.start = () => { };
DMXKingUltraDMXPro.prototype.stop = () => { };
DMXKingUltraDMXPro.prototype.close = function (cb) {
this.dev.close(cb);
};
DMXKingUltraDMXPro.prototype.update = function (u) {
for (const c in u) {
this.universe[c] = u[c];
}
this.sendUniverse();
};
DMXKingUltraDMXPro.prototype.updateAll = function (v) {
for (let i = 1; i <= 512; i++) {
this.universe[i] = v;
}
this.sendUniverse();
};
DMXKingUltraDMXPro.prototype.get = function (c) {
return this.universe[c];
};
module.exports = DMXKingUltraDMXPro;

View file

@ -1,75 +0,0 @@
const SerialPort = require('serialport');
function EnttecOpenUsbDMX(deviceId, options) {
const self = this;
options = options || {};
this.universe = new Buffer(513);
this.universe.fill(0);
self.interval = 46;
this.dev = new SerialPort(deviceId, {
'baudRate': 250000,
'dataBits': 8,
'stopBits': 2,
'parity': 'none',
}, err => {
if (err) {
console.log(err);
return;
}
self.start();
});
}
EnttecOpenUsbDMX.prototype.sendUniverse = function () {
const self = this;
if (!this.dev.writable) {
return;
}
// toggle break
self.dev.set({brk: true, rts: true}, (err, r) => {
setTimeout(() => {
self.dev.set({brk: false, rts: true}, (err, r) => {
setTimeout(() => {
self.dev.write(Buffer.concat([Buffer([0]), self.universe.slice(1)]));
}, 1);
});
}, 1);
});
};
EnttecOpenUsbDMX.prototype.start = function () {
this.intervalhandle = setInterval(this.sendUniverse.bind(this), this.interval);
};
EnttecOpenUsbDMX.prototype.stop = function () {
clearInterval(this.intervalhandle);
};
EnttecOpenUsbDMX.prototype.close = function (cb) {
this.stop();
this.dev.close(cb);
};
EnttecOpenUsbDMX.prototype.update = function (u) {
for (const c in u) {
this.universe[c] = u[c];
}
};
EnttecOpenUsbDMX.prototype.updateAll = function (v) {
for (let i = 1; i <= 512; i++) {
this.universe[i] = v;
}
};
EnttecOpenUsbDMX.prototype.get = function (c) {
return this.universe[c];
};
module.exports = EnttecOpenUsbDMX;

View file

@ -1,72 +0,0 @@
const SerialPort = require('serialport');
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;
function EnttecUSBDMXPRO(deviceId, options = {}) {
const self = this;
this.universe = Buffer.alloc(513, 0);
this.dev = new SerialPort(deviceId, {
'baudRate': 250000,
'dataBits': 8,
'stopBits': 2,
'parity': 'none',
}, err => {
if (!err) {
self.sendUniverse();
}
});
}
EnttecUSBDMXPRO.prototype.sendUniverse = function () {
if (!this.dev.writable) {
return;
}
const hdr = Buffer.from([
ENTTEC_PRO_START_OF_MSG,
ENTTEC_PRO_SEND_DMX_RQ,
(this.universe.length) & 0xff,
((this.universe.length) >> 8) & 0xff,
ENTTEC_PRO_DMX_STARTCODE,
]);
const msg = Buffer.concat([
hdr,
this.universe.slice(1),
Buffer.from([ENTTEC_PRO_END_OF_MSG]),
]);
this.dev.write(msg);
};
EnttecUSBDMXPRO.prototype.start = () => { };
EnttecUSBDMXPRO.prototype.stop = () => { };
EnttecUSBDMXPRO.prototype.close = function (cb) {
this.dev.close(cb);
};
EnttecUSBDMXPRO.prototype.update = function (u) {
for (const c in u) {
this.universe[c] = u[c];
}
this.sendUniverse();
};
EnttecUSBDMXPRO.prototype.updateAll = function (v) {
for (let i = 1; i <= 512; i++) {
this.universe[i] = v;
}
this.sendUniverse();
};
EnttecUSBDMXPRO.prototype.get = function (c) {
return this.universe[c];
};
module.exports = EnttecUSBDMXPRO;

View file

@ -1,42 +0,0 @@
function Null(deviceId, options) {
const self = this;
options = options || {};
this.universe = Buffer.alloc(513, 0);
self.start();
}
Null.prototype.start = function () {
const self = this;
self.timeout = setInterval(() => {
console.log(self.universe);
}, 1000);
};
Null.prototype.stop = function () {
clearInterval(this.timeout);
};
Null.prototype.close = cb => {
cb(null);
};
Null.prototype.update = function (u) {
for (const c in u) {
this.universe[c] = u[c];
}
console.log(this.universe.slice(1));
};
Null.prototype.updateAll = function (v) {
for (let i = 1; i <= 512; i++) {
this.universe[i] = v;
}
};
Null.prototype.get = function (c) {
return this.universe[c];
};
module.exports = Null;

191
easing.js
View file

@ -1,191 +0,0 @@
/*
* based on jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
*
* TERMS OF USE - jQuery Easing
*
* Open source under the BSD License.
*
* Copyright © 2008 George McGinley Smith
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the author nor the names of contributors may be used to endorse
* or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// t: current time, b: begInnIng value, c: change In value, d: duration
exports.ease = {
linear(t, b, c, d) { return c * t / d + b; },
inQuad(t, b, c, d) { return c * (t /= d) * t + b; },
outQuad(t, b, c, d) { return -c * (t /= d) * (t - 2) + b; },
inOutQuad(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
return -c / 2 * ((--t) * (t - 2) - 1) + b;
},
inCubic(t, b, c, d) { return c * (t /= d) * t * t + b; },
outCubic(t, b, c, d) { return c * ((t = t / d - 1) * t * t + 1) + b; },
inOutCubic(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
return c / 2 * ((t -= 2) * t * t + 2) + b;
},
inQuart(t, b, c, d) {
return c * (t /= d) * t * t * t + b;
},
outQuart(t, b, c, d) {
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
},
inOutQuart(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
},
inQuint(t, b, c, d) {
return c * (t /= d) * t * t * t * t + b;
},
outQuint(t, b, c, d) {
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
},
inOutQuint(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
},
inSine(t, b, c, d) {
return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
},
outSine(t, b, c, d) {
return c * Math.sin(t / d * (Math.PI / 2)) + b;
},
inOutSine(t, b, c, d) {
return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
},
inExpo(t, b, c, d) {
return (t === 0) ? b : c * (2 ** (10 * (t / d - 1))) + b;
},
outExpo(t, b, c, d) {
return (t === d) ? b + c : c * (-(2 ** (-10 * t / d)) + 1) + b;
},
inOutExpo(t, b, c, d) {
if (t === 0) return b;
if (t === d) return b + c;
if ((t /= d / 2) < 1) return c / 2 * (2 ** (10 * (t - 1))) + b;
return c / 2 * (-(2 ** (-10 * --t)) + 2) + b;
},
inCirc(t, b, c, d) {
return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
},
outCirc(t, b, c, d) {
return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
},
inOutCirc(t, b, c, d) {
if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
},
inElastic(t, b, c, d) {
let s = 1.70158; let p = 0; let a = c;
if (t === 0) return b; if ((t /= d) === 1) return b + c; if (!p) p = d * 0.3;
if (a < Math.abs(c)) { a = c; s = p / 4; } else s = p / (2 * Math.PI) * Math.asin(c / a);
return -(a * (2 ** (10 * (t -= 1))) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
},
outElastic(t, b, c, d) {
let s = 1.70158; let p = 0; let a = c;
if (t === 0) return b; if ((t /= d) === 1) return b + c; if (!p) p = d * 0.3;
if (a < Math.abs(c)) { a = c; s = p / 4; } else s = p / (2 * Math.PI) * Math.asin(c / a);
return a * (2 ** (-10 * t)) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
},
inOutElastic(t, b, c, d) {
let s = 1.70158; let p = 0; let a = c;
if (t === 0) return b; if ((t /= d / 2) === 2) return b + c; if (!p) p = d * (0.3 * 1.5);
if (a < Math.abs(c)) { a = c; s = p / 4; } else s = p / (2 * Math.PI) * Math.asin(c / a);
if (t < 1) return -0.5 * (a * (2 ** (10 * (t -= 1))) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
return a * (2 ** (-10 * (t -= 1))) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
},
inBack(t, b, c, d, s) {
if (s === undefined) s = 1.70158;
return c * (t /= d) * t * ((s + 1) * t - s) + b;
},
outBack(t, b, c, d, s) {
if (s === undefined) s = 1.70158;
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
},
inOutBack(t, b, c, d, s) {
if (s === undefined) s = 1.70158;
if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
},
inBounce(t, b, c, d) {
return c - exports.ease.outBounce(d - t, 0, c, d) + b;
},
outBounce(t, b, c, d) {
if ((t /= d) < (1 / 2.75)) {
return c * (7.5625 * t * t) + b;
} else if (t < (2 / 2.75)) {
return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
} else if (t < (2.5 / 2.75)) {
return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
}
return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
},
inOutBounce(t, b, c, d) {
if (t < d / 2) return exports.ease.inBounce(t * 2, 0, c, d) * 0.5 + b;
return exports.ease.outBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
},
};
/*
*
* TERMS OF USE - EASING EQUATIONS
*
* Open source under the BSD License.
*
* Copyright © 2001 Robert Penner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the author nor the names of contributors may be used to endorse
* or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

View file

@ -1,28 +1,27 @@
{ {
"name": "dmx", "name": "@node-dmx/dmx-web",
"version": "0.2.0", "version": "1.0.0",
"author": "Sebastian Wiedenroth <wiedi@frubar.net>", "author": "Sebastian Wiedenroth <wiedi@frubar.net>",
"description": "DMX library and webservice", "description": "DMX webservice and web ui powered by node-dmx",
"url": "https://github.com/node-dmx/node-dmx", "url": "https://github.com/node-dmx/node-dmx-web",
"bin": { "bin": {
"dmx-web": "./dmx.js" "dmx-web": "./dmx-web.js"
}, },
"scripts": { "scripts": {
"test": "node_modules/eslint/bin/eslint.js -c .eslintrc .; exit 0" "test": "node_modules/eslint/bin/eslint.js -c .eslintrc .; exit 0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/node-dmx/node-dmx.git" "url": "https://github.com/node-dmx/node-dmx-web.git"
}, },
"keywords": [ "keywords": [
"DMX", "DMX",
"light control" "light control"
], ],
"dependencies": { "dependencies": {
"body-parser": "^1.5.2", "@node-dmx/dmx-library": "^0.2.0",
"commander": "^2.12.2", "commander": "^2.12.2",
"express": "^4.16.2", "express": "^4.16.2",
"serialport": "^6.0.4",
"socket.io": "^2.0.4" "socket.io": "^2.0.4"
}, },
"devDependencies": { "devDependencies": {

View file

@ -1,16 +1,16 @@
# node-dmx # node-dmx
DMX-512 controller library for node.js - also includes a Webinterface and HTTP API. Webinterface and HTTP API using node-dmx
## Install ## Install
npm install -g dmx `npm install`
## Webinterface ## Webinterface
### Configuration ### Configuration
The Daemon <code>dmx-web</code> looks for a configuration file in <code>/etc/dmx-web.json</code>. An alternate location can be passed as a command line argument. The Daemon `dmx-web` looks for a configuration file in `/etc/dmx-web.json`. An alternate location can be passed as a command line argument.
This configuration file consists of three sections: This configuration file consists of three sections:
@ -22,21 +22,21 @@ In the Server section you can set the listen port and host.
Under Universes you describe the DMX Universes with details like which output driver to use and which devices are at which address. Under Universes you describe the DMX Universes with details like which output driver to use and which devices are at which address.
The presets section allows you to specify a state some channels should be set when the preset is called. The presets section allows you to specify a state some channels should be set when the preset is called.
A example configuration is in the repository by the name <code>dmx-web-example.conf</code> A example configuration is in the repository by the name `dmx-web-example.conf`
### Run ### Run
dmx-web [-c <full-path to config file>] `dmx-web [-c <full-path to config file>]`
### Run as a service ### Run as a service
On MacOS you can run dmx-web as a service by adding a launch script to /Library/LaunchDaemons. See the example file. On MacOS you can run dmx-web as a service by adding a launch script to `/Library/LaunchDaemons`. See the example file.
### Animation HTTP API ### Animation HTTP API
A List of Channel Transistions can be POSTed to <code>/animation/&lt;universe&gt;</code>. Each transistion is a JSON Object with at least the <code>to</code> property present. The Value of which also has to be an Object describing the channel end-states. A List of Channel Transistions can be POSTed to `/animation/&lt;universe&gt;`. Each transistion is a JSON Object with at least the `to` property present. The Value of which also has to be an Object describing the channel end-states.
A duration for this transistion can be given in the <code>duration</code> property. A duration for this transistion can be given in the `duration` property.
If not specified 0ms is assumed. If not specified 0ms is assumed.
Example: Example:
@ -51,7 +51,7 @@ This sets channels 10 and 20 to zero. Then transistions channel 10 to 255 in 2 s
## Library API ## Library API
var DMX = require('dmx') var DMX = require('@node-dmx/dmx-library')
### Class DMX ### Class DMX
@ -61,8 +61,8 @@ Create a new DMX instance. This class is used to tie multiple universes together
#### dmx.registerDriver(name, module) #### dmx.registerDriver(name, module)
- <code>name</code> - String - `name` - String
- <code>module</code> - Object implementing the Driver API - `module` - Object implementing the Driver API
Register a new DMX Driver module by its name. Register a new DMX Driver module by its name.
@ -78,26 +78,26 @@ These drivers are currently registered by default:
#### dmx.addUniverse(name, driver, device_id, options) #### dmx.addUniverse(name, driver, device_id, options)
- <code>name</code> - String - `name` - String
- <code>driver</code> - String, referring a registered driver - `driver` - String, referring a registered driver
- <code>device_id</code> - Number or Object - `device_id` - Number or Object
- <code>options</code> - Object, driver specific options - `options` - Object, driver specific options
Add a new DMX Universe with a name, driver and an optional device_id used by the driver to identify the device. Add a new DMX Universe with a name, driver and an optional device_id used by the driver to identify the device.
For enttec-usb-dmx-pro and enttec-open-usb-dmx device_id is the path the the serial device. For artnet it is the target ip. For enttec-usb-dmx-pro and enttec-open-usb-dmx device_id is the path the the serial device. For artnet it is the target ip.
#### dmx.update(universe, channels) #### dmx.update(universe, channels)
- <code>universe</code> - String, name of the universe - `universe` - String, name of the universe
- <code>channels</code> - Object, keys are channel numbers, values the values to set that channel to - `channels` - Object, keys are channel numbers, values the values to set that channel to
Update one or multiple channels of a universe. Also emits a <code>update</code> Event with the same information. Update one or multiple channels of a universe. Also emits a `update` Event with the same information.
#### DMX.devices #### DMX.devices
A JSON Object describing some Devices and how many channels they use. A JSON Object describing some Devices and how many channels they use.
Currently not many devices are in there but more can be added to the <code>devices.js</code> file. Pull requests welcome ;-) Currently not many devices are in there but more can be added to the `devices.js` file. Pull requests welcome ;-)
The following Devices are known: The following Devices are known:
@ -114,12 +114,12 @@ Create a new DMX Animation instance. This can be chained similar to jQuery.
#### animation.add(to, duration, options) #### animation.add(to, duration, options)
- <code>to</code> - Object, keys are channel numbers, values the values to set that channel to - `to` - Object, keys are channel numbers, values the values to set that channel to
- <code>duration</code> - Number, duration in ms - `duration` - Number, duration in ms
- <code>options</code> - Object - `options` - Object
Add an animation Step. Add an animation Step.
The options Object takes an <code>easing</code> key which allows to set a easing function from the following list: The options Object takes an `easing` key which allows to set a easing function from the following list:
- linear (default) - linear (default)
- inQuad - inQuad
@ -158,7 +158,7 @@ Returns a Animation object with the animation step added.
#### animation.delay(duration) #### animation.delay(duration)
- <code>duration</code> - Number, duration in ms - `duration` - Number, duration in ms
Delay the next animation step for duration. Delay the next animation step for duration.
Returns a Animation object with the delay step added. Returns a Animation object with the delay step added.
@ -166,8 +166,8 @@ Returns a Animation object with the delay step added.
#### animation.run(universe, onFinish) #### animation.run(universe, onFinish)
- <code>universe</code> - Object, reference to the universe driver - `universe` - Object, reference to the universe driver
- <code>onFinish</code> - Function, called when the animation is done - `onFinish` - Function, called when the animation is done
Run the Animation on the specified universe. Run the Animation on the specified universe.