diff --git a/.gitignore b/.gitignore index 6568e15..8232012 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ results .DS_Store node_modules +.project +.com.greenworldsoft.syncfolderspro diff --git a/com.dmx-web.server.example.plist b/com.dmx-web.server.example.plist new file mode 100644 index 0000000..3be95c5 --- /dev/null +++ b/com.dmx-web.server.example.plist @@ -0,0 +1,27 @@ + + + + + RunAtLoad + + KeepAlive + + Label + com.dmx-web.server + ProgramArguments + + /usr/local/bin/dmx-web + -c + /Library/Server/DMX/dmx-web.json + + StandardOutPath + /Library/Logs/homebridge/dmxlogfile.log + StandardErrorPath + /Library/Logs/homebridge/dmxlogfile.log + EnvironmentVariables + + PATH + /usr/local/bin/:$PATH + + + diff --git a/devices.js b/devices.js index 70fc349..99256e0 100644 --- a/devices.js +++ b/devices.js @@ -50,5 +50,15 @@ module.exports = { ] } } + }, + 'ultra-pro-24ch-rdm': { + channels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24' ], + ranges: { + 'dimmer': { + 'type': 'slider', + 'min': 0, + 'max': 255 + } + } } } \ No newline at end of file diff --git a/dmx-web-example.conf b/dmx-web-example.conf index f470862..bde5ca0 100644 --- a/dmx-web-example.conf +++ b/dmx-web-example.conf @@ -1,76 +1,143 @@ -module.exports = { +{ "server": { "listen_port": 8080, "listen_host": "::", - // drop privileges to: - // "uid": "www-data", - // "gid": "www-data" + "comment1": "On linux drop privileges by adding the following lines: uid: www-data and gid: www-data", + "comment2": "On Macos uid and gid must be set in the launchd script." }, "presets": [ { - label: "White", - values: { - 'office': { 0:16, 1:255, 2:0, 3:255, 4: 255, 5:255, 15:16, 16:255, 17:0, 18:255, 19: 255, 20:255 } + "label": "White", + "values": { + "office": { "0":16, "1":255, "2":0, "3":255, "4": 255, "5":255, "15":16, "16":255, "17":0, "18":255, "19": 255, "20":255 } } }, { - label: 'Natural', - values: { - 'office': { 0:16, 1:255, 2:0, 3:255, 4: 190, 5:140, 15:16, 16:255, 17:0, 18:255, 19: 190, 20:140 } + "label": "Natural", + "values": { + "office": { "0":16, "1":255, "2":0, "3":255, "4": 190, "5":140, "15":16, "16":255, "17":0, "18":255, "19": 190, "20":140 } } }, { - label: 'Worklight', - values: { - 'office': { 0:16, 1:130, 2:0, 3:255, 4: 165, 5:0, 15: 1, 16:255, 17:0, 18:255, 19: 190, 20:140, 21:0, 22: 0, 23:0, 24:255, 25: 190, 26:140 } + "label": "Worklight", + "values": { + "office": { "0":16, "1":130, "2":0, "3":255, "4": 165, "5":0, "15": 1, "16":255, "17":0, "18":255, "19": 190, "20":140, "21":0, "22": 0, "23":0, "24":255, "25": 190, "26":140 } } }, { - label: 'Chill', - values: { - 'office': { 0:16, 1:255, 2:0, 3:255, 4: 39, 5:0, 15: 1, 16:255, 17:0, 18:255, 19: 255, 20:0, 21:0, 22: 0, 23:0, 24:128, 25: 0, 26:255, 31:255, 32: 60 } + "label": "Chill", + "values": { + "office": { "0":16, "1":255, "2":0, "3":255, "4": 39, "5":0, "15": 1, "16":255, "17":0, "18":255, "19": 255, "20":0, "21":0, "22": 0, "23":0, "24":128, "25": 0, "26":255, "31":255, "32": 60 } } }, { - label: 'Cinema', - values: { - 'office': { 0:16, 1:30, 2:0, 3:255, 4: 39, 5:0, 15:0, 31:255, 32:0 } + "label": "Cinema", + "values": { + "office": { "0":16, "1":30, "2":0, "3":255, "4": 39, "5":0, "15":0, "31":255, "32":0 } } - }, + } ], - universes: { - 'office': { - 'output': { - // 'driver': 'enttec-usb-dmx-pro', - // 'device': '/dev/cu.usbserial-6AVNHXS8' - 'driver': 'null', - 'device': 0 + "universes": { + "office": { + "output": { + "driver": "enttec-usb-dmx-pro", + "device": "/dev/cu.usbserial-6A1KQK87" }, - 'devices': [ + "devices": [ { - 'type': 'eurolite-led-bar', - 'address': 0 + "type": "eurolite-led-bar", + "address": 0 }, { - 'type': 'eurolite-led-bar', - 'address': 15 + "type": "eurolite-led-bar", + "address": 15 }, { - 'type': 'showtec-multidim2', - 'address': 31 + "type": "showtec-multidim2", + "address": 31 }, { - 'type': 'stairville-led-par-56', - 'address': 64 + "type": "stairville-led-par-56", + "address": 64 }, { - 'type': 'stairville-led-par-56', - 'address': 70 + "type": "stairville-led-par-56", + "address": 70 }, { - 'type': 'stairville-led-par-56', - 'address': 76 + "type": "stairville-led-par-56", + "address": 76 + } + ] + }, + "bedroom": { + "output": { + "driver": "dmxking-ultra-dmx-pro", + "device": "/dev/cu.usbserial-6AVNHXS8", + "options": { + "port": "A" + } + }, + "devices": [ + { + "type": "eurolite-led-bar", + "address": 0 + }, + { + "type": "eurolite-led-bar", + "address": 15 + }, + { + "type": "showtec-multidim2", + "address": 31 + }, + { + "type": "stairville-led-par-56", + "address": 64 + }, + { + "type": "stairville-led-par-56", + "address": 70 + }, + { + "type": "stairville-led-par-56", + "address": 76 + } + ] + }, + "livingroom": { + "output": { + "driver": "dmxking-ultra-dmx-pro", + "device": "/dev/cu.usbserial-6AVNHXS8", + "options": { + "port": "B" + } + }, + "devices": [ + { + "type": "eurolite-led-bar", + "address": 0 + }, + { + "type": "eurolite-led-bar", + "address": 15 + }, + { + "type": "showtec-multidim2", + "address": 31 + }, + { + "type": "stairville-led-par-56", + "address": 64 + }, + { + "type": "stairville-led-par-56", + "address": 70 + }, + { + "type": "stairville-led-par-56", + "address": 76 } ] } diff --git a/dmx-web.js b/dmx-web.js index 9f1dd99..06073df 100755 --- a/dmx-web.js +++ b/dmx-web.js @@ -28,7 +28,8 @@ function DMXWeb() { dmx.addUniverse( universe, config.universes[universe].output.driver, - config.universes[universe].output.device + config.universes[universe].output.device, + config.universes[universe].output.options ) } diff --git a/dmx.js b/dmx.js index 78c937a..45d4695 100644 --- a/dmx.js +++ b/dmx.js @@ -9,12 +9,13 @@ function DMX(options) { this.drivers = {} this.devices = options.devices || require('./devices') - 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('artnet', require('./drivers/artnet')) - this.registerDriver('bbdmx', require('./drivers/bbdmx')) + 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')) } util.inherits(DMX, EventEmitter) @@ -26,8 +27,8 @@ DMX.prototype.registerDriver = function(name, module) { this.drivers[name] = module } -DMX.prototype.addUniverse = function(name, driver, device_id) { - return this.universes[name] = new this.drivers[driver](device_id) +DMX.prototype.addUniverse = function(name, driver, device_id, options) { + return this.universes[name] = new this.drivers[driver](device_id, options) } DMX.prototype.update = function(universe, channels) { diff --git a/drivers/dmxking-ultra-dmx-pro.js b/drivers/dmxking-ultra-dmx-pro.js new file mode 100644 index 0000000..6805bd8 --- /dev/null +++ b/drivers/dmxking-ultra-dmx-pro.js @@ -0,0 +1,84 @@ +"use strict" + +var SerialPort = require("serialport") + +var DMXKING_ULTRA_DMX_PRO_DMX_STARTCODE = 0x00 + , DMXKING_ULTRA_DMX_PRO_START_OF_MSG = 0x7e + , DMXKING_ULTRA_DMX_PRO_END_OF_MSG = 0xe7 + , DMXKING_ULTRA_DMX_PRO_SEND_DMX_RQ = 0x06 + , DMXKING_ULTRA_DMX_PRO_SEND_DMX_A_RQ = 0x64 + , DMXKING_ULTRA_DMX_PRO_SEND_DMX_B_RQ = 0x65 + , DMXKING_ULTRA_DMX_PRO_RECV_DMX_PKT = 0x05 + ; + +function DMXKingUltraDMXPro(device_id, options) { + var self = this + this.options = options || {} + this.universe = new Buffer(512) + this.universe.fill(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(device_id, { + 'baudrate': 250000, + 'databits': 8, + 'stopbits': 2, + 'parity': 'none' + }, function(err) { + if(!err) { + self.send_universe() + } + }) +} + +DMXKingUltraDMXPro.prototype.send_universe = function() { + if(!this.dev.isOpen()) { + return + } + var hdr = Buffer([ + DMXKING_ULTRA_DMX_PRO_START_OF_MSG, + this.sendDMXReq, + (this.universe.length + 1) & 0xff, + ((this.universe.length + 1) >> 8) & 0xff, + DMXKING_ULTRA_DMX_PRO_DMX_STARTCODE + ]) + + var msg = Buffer.concat([ + hdr, + this.universe, + Buffer([DMXKING_ULTRA_DMX_PRO_END_OF_MSG]) + ]) + this.dev.write(msg) +} + +DMXKingUltraDMXPro.prototype.start = function() {} +DMXKingUltraDMXPro.prototype.stop = function() {} + +DMXKingUltraDMXPro.prototype.close = function(cb) { + this.dev.close(cb) +} + +DMXKingUltraDMXPro.prototype.update = function(u) { + for(var c in u) { + this.universe[c] = u[c] + } + this.send_universe() +} + +DMXKingUltraDMXPro.prototype.updateAll = function(v){ + for(var i = 0; i < 512; i++) { + this.universe[i] = v + } + this.send_universe() +} + +DMXKingUltraDMXPro.prototype.get = function(c) { + return this.universe[c] +} + +module.exports = DMXKingUltraDMXPro \ No newline at end of file diff --git a/readme.md b/readme.md index d4ebf30..b33287b 100644 --- a/readme.md +++ b/readme.md @@ -28,6 +28,10 @@ A example configuration is in the repository by the name dmx-web-example.c dmx-web [-c ] +### 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. + ### Animation HTTP API A List of Channel Transistions can be POSTed to /animation/<universe>. 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. @@ -70,12 +74,14 @@ These drivers are currently registered by default: - dmx4all: driver for DMX4ALL devices like the "NanoDMX USB Interface" - enttec-usb-dmx-pro: a driver for devices using a Enttec USB DMX Pro chip like the "DMXKing ultraDMX Micro". - enttec-open-usb-dmx: driver for "Enttec Open DMX USB". This device is NOT recommended, there are known hardware limitations and this driver is not very stable. (If possible better obtain a device with the "pro" chip) +- dmxking-utra-dmx-pro: driver for the DMXKing Ultra DMX pro interface. This driver support multiple universe specify the options with Port = A or B -#### dmx.addUniverse(name, driver, device_id) +#### dmx.addUniverse(name, driver, device_id, options) - name - String - driver - String, referring a registered driver - device_id - Number or Object +- 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. 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.