Giter VIP home page Giter VIP logo

e131-node's Introduction

Node.js library for the E1.31 (sACN) protocol

A Node.js module that provides simple client and server objects for communicating with devices using the E1.31 (sACN) protocol. A lot of information about E.131 (sACN) can be found on this Wiki article.

Installation

To install, use npm:

$ npm install e131

Client Class

The Client class implements a UDP client for sending E1.31 (sACN) traffic. The class constructor is as follows:

var e131 = require('e131');
var client = new e131.Client(arg, [port]);

The first argument can be a host address, name or universe number. If port is omitted, the default E1.31 port 5568 is used. If a universe is given, the client will automatically join the relevant Multicast group. The client automatically increments (and wraps around if necessary) the sequence number of the transmitted packet.

The client provides two methods:

  • createPacket(numSlots): creates a new E1.31 (sACN) packet to be used for sending.
  • send(packet): sends a E1.31 (sACN) packet to the remote host or multicast group.

Full code example for the Client class:

var e131 = require('e131');

var client = new e131.Client('192.168.1.12');  // or use a universe
var packet = client.createPacket(24);  // we want 8 RGB (x3) slots
var slotsData = packet.getSlotsData();
packet.setSourceName('test E1.31 client');
packet.setUniverse(0x01);  // make universe number consistent with the client
packet.setOption(packet.Options.PREVIEW, true);  // don't really change any fixture
packet.setPriority(packet.DEFAULT_PRIORITY);  // not strictly needed, done automatically

// slotsData is a Buffer view, you can use it directly
var color = 0;
function cycleColor() {
  for (var idx=0; idx<slotsData.length; idx++) {
    slotsData[idx] = color % 0xff;
    color = color + 90;
  }
  client.send(packet, function () {
    setTimeout(cycleColor, 125);
  });
}
cycleColor();

Server Class

The Server class implements a UDP server for receiving E1.31 (sACN) traffic. The class constructor is as follows:

var e131 = require('e131');
var server = new e131.Server([universes], [port]);

The universes argument can be an array (for joining multiple universes) or a single integer for joining a single universe. If universes is omitted, a single value of 1 is assumed.

Note: This library only uses one UDP socket and there is a maximum limit of 20 multicast memberships (universes) per single UDP socket. See issue #17 for more details.

If port is omitted, the default E1.31 port 5568 is used. The server will join the corresponding Multicast groups for each provided universe automatically and starts listening as soon as it is created. The server performs basic out-of-order detection on received packets. If an out-of-order packet is received, it is discarded.

The server supports the following events that you can listen to:

  • listening: fires as soon as the server starts listening.
  • close: fires when the server is closed.
  • error: fires when an error occurs within the server.
  • packet: (packet) fires when a valid E1.31 (sACN) packet is received.
  • packet-out-of-order: (packet) fires when an out-of-order packet is received.
  • packet-error: (packet, err) fires when an invalid packet is received.

Full code example for the Server class:

var e131 = require('e131');

var server = new e131.Server([0x0001, 0x0002]);
server.on('listening', function() {
  console.log('server listening on port %d, universes %j', this.port, this.universes);
});
server.on('packet', function (packet) {
  var sourceName = packet.getSourceName();
  var sequenceNumber = packet.getSequenceNumber();
  var universe = packet.getUniverse();
  var slotsData = packet.getSlotsData();

  console.log('source="%s", seq=%d, universe=%d, slots=%d',
    sourceName, sequenceNumber, universe, slotsData.length);
  console.log('slots data = %s', slotsData.toString('hex'));
});

E1.31 (sACN) Packet Class

The E1.31 Packet class contains a number of useful setter methods:

  • setCID(uuid): sets the CID field into the root layer.
  • setSourceName(name): sets source name field into the frame layer.
  • setPriority(priority): sets the priority field into the frame layer.
  • setSequenceNumber(number): sets the sequence number into the frame layer.
  • setOption(option, state): sets the state of a framing option into the frame layer.
  • setUniverse(universe): sets the DMX universe into the frame layer.
  • setSlotsData(buffer): sets the DMX slots data into the DMP layer.

Also the following getter methods are provided:

  • getCID(): gets the CID field from the root layer.
  • getSourceName(): gets the source name field from the frame layer.
  • getPriority(): gets the priority field from the frame layer.
  • getSequenceNumber(): gets the sequence number from the frame layer.
  • getOption(option): gets the state of a framing option from the frame layer.
  • getUniverse(): gets the DMX universe from the frame layer.
  • getSlotsData(): gets the DMX slots data from the DMP layer.

Available E1.31 framing options are:

  • Options.TERMINATED: the current packet is the last one in the stream. The receiver should stop processing further packets.
  • Options.PREVIEW: the data in the packet should be only used for preview purposes, e.g. console display, and not to drive live fixtures.

Available constants in the Packet class are:

  • DEFAULT_PRIORITY: the default priority number used to initialize new packets.

If a packet fails validation, the following errors can be returned:

  • ERR_ROOT_LAYER: mismatch in the ACN PID or vector fields of the root layer.
  • ERR_FRAME_LAYER: mismatch in the vector field of the frame layer.
  • ERR_DMP_LAYER: mismatch in the type, addresses or vector fields of the DMP layer.

e131-node's People

Contributors

afontaine-chipkin avatar atoudam avatar hhromic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

e131-node's Issues

Connecting to a PixLite MKII

Hey there, I'm trying to figure out how I can use this library to control the LEDs on a PixLite MKII.

http://www.advateklights.com/shop/pixlite-pixel-mapping/50-pixlite-16-mkii-control-board.html

It says it supports sACN E1.31 so I figured this would be the perfect library to use. :)

Perhaps I'm misunderstanding the library, but how to I control a specific LED or set of LEDs using this library?

I ran the demo code, but it doesn't seem to be working.

I've set the static IP address and I have the universe and channel number:

image

image

Now I'm running the code... I'm confused about what the packet is and how to fill the buffer in order to trigger certain LEDs. Furthermore, the controller has server LED banks to choose from on the hardware side and I have no idea where that is specified in this library.

const e131 = require("e131")

// Open Advatek Assistant to connect to the controller and set the static IP
const ipAddress = "192.0.1.52"

var client = new e131.Client(ipAddress) // or use a universe
var packet = client.createPacket(24) // we want 8 RGB (x3) slots
var slotsData = packet.getSlotsData()
packet.setSourceName("test E1.31 client")
packet.setUniverse(0x01) // make universe number consistent with the client
// packet.setOption(packet.Options.PREVIEW, true) // don't really change any fixture
packet.setPriority(packet.DEFAULT_PRIORITY) // not strictly needed, done automatically

// slotsData is a Buffer view, you can use it directly
var color = 0
function cycleColor() {
	for (var idx = 0; idx < slotsData.length; idx++) {
		slotsData[idx] = color % 0xff
		color = color + 90
	}
	client.send(packet, function() {
		setTimeout(cycleColor, 125)
	})
}
cycleColor()

Anyways, I would appreciate any help or suggestions you have :)

Max limit of 20 Universes as a E131 Server

When creating a new server using the e131.Server function and passing in an array of more than 20 universes, the application crashes with the following error:

Error: addMembership ENOBUFS
    at Socket.addMembership (dgram.js:830:11)
    at X:/dev/node_modules/e131/lib/server.js:74:20
    at Array.forEach (<anonymous>)
    at Socket.onListening (X:/dev/node_modules/e131/lib/server.js:71:20)
    at Socket.onListening (dgram.js:225:10)
    at Socket.emit (events.js:326:22)
    at Socket.EventEmitter.emit (domain.js:506:15)
    at startListening (dgram.js:150:10)
    at dgram.js:345:7
    at processTicksAndRejections (internal/process/task_queues.js:85:21)

Trying to research around the internet, I eventually found the following article:
https://www.ibm.com/docs/en/zos/2.1.0?topic=options-ip-add-membership-ip-drop-membership

The article specifies the following:
"However, there is a maximum limit of 20 groups for a single UDP socket, and there is a maximum limit of 256 groups for a single RAW socket"

Since this library uses a UDP socket, there is a max limit of 20 universes per socket.

dgram: Offset + length beyond buffer length

Hi, I tried your example to create a packet and received an error of dgram:

root@smarthome:~# node e131test.js
dgram.js:300
throw new RangeError('Offset + length beyond buffer length');
^

RangeError: Offset + length beyond buffer length
at Socket.send (dgram.js:300:11)
at Client.send (/root/node_modules/e131/lib/client.js:49:16)
at cycleColor (/root/e131test.js:16:10)
at Object. (/root/e131test.js:20:1)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)

e131test.js:

var e131 = require('e131');
var client = new e131.Client('192.168.178.135');
var packet = client.createPacket(3);
var slotsData = packet.getSlotsData();

packet.setSourceName('test E1.31 client');
packet.setUniverse(0x01);
packet.setOption(packet.Options.PREVIEW, false);
packet.setPriority(packet.DEFAULT_PRIORITY);

var color = 0; function cycleColor() {
for (var idx=0; idx<slotsData.length; idx++) {
slotsData[idx] = color % 0xff;
color = color + 90;
}
client.send(packet, function () {
setTimeout(cycleColor, 125);
});
}
cycleColor();

Channel data mixes with priority

Using node red, i encountered an issue where slotsdata contains priority info.
payload with priority (values equaling 1)
10 Jul 10:39:46 - [info] [debug:bb13e6a0.6360b8] <Buffer 01 01 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 462 more bytes>

payload with intensity
10 Jul 10:39:46 - [info] [debug:bb13e6a0.6360b8] <Buffer 00 00 00 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 462 more bytes>

the node red implementation forwards data from .getSlotsData() to payload

Error [ERR_SOCKET_CANNOT_SEND]: Unable to send data

Error [ERR_SOCKET_CANNOT_SEND]: Unable to send data
at Socket.onListenError (dgram.js:386:22)
at Object.onceWrapper (events.js:285:13)
at Socket.emit (events.js:197:13)
at state.handle.lookup (dgram.js:301:14)
at processTicksAndRejections (internal/process/next_tick.js:76:17)
Emitted 'error' event at:
at Socket.onListenError (dgram.js:386:8)
at Object.onceWrapper (events.js:285:13)
[... lines matching original stack trace ...]
at processTicksAndRejections (internal/process/next_tick.js:76:17)

Could you please help me to resolved this issue?

Client only sends on 1 network interface

Currently the client sends multicast on the first interface. If the computer has multiple network cards then it would be good to be able to specify which one is used.

Here is an implementation for setting the interface

// E1.31 client object constructor
function Client(arg, port) {
  if (this instanceof Client === false) {
    return new Client(arg, port);
  }

  if (arg === undefined) {
    throw new TypeError('arg should be a host address, name or universe');
  }

  this.host = Number.isInteger(arg) ? e131.getMulticastGroup(arg) : arg;
  this.port = port || e131.DEFAULT_PORT;
  this._socket = dgram.createSocket('udp4');

  this._socket.bind(5568, () => {
    this._socket.setMulticastInterface('10.50.106.2');
  });
}

Is there any preference in how the default is treated? I think one option could be to keep the current functionality and only bind if the the Client is called with a ip address.

There is a pull request for server that implements similar functionality https://github.com/hhromic/e131-node/pull/7/files

Server only works with a single network interface

When running on a machine with multiple network interfaces only the primary interface works. Im my use case sACN is on an isolated network. This can be fixed by specifying the IP of the desired interface when calling _socket.addMembership.

As a work around I am calling

dmx.on("listening", function() {
    const multicastGroup = "239.255." + (universe >> 8) + "." + (universe & 0xff);
    dmx._socket.addMembership(multicastGroup, dmxInterfaceIP);

Sending multiple universes

Sacn supports many universes. When using the client, is it possible to send more than one universe at the same time?

Error with Buffer

I trying to use library with electron.io and got an error:
TypeError: undefined is not a function
at Object. (/home/dehimer/projects/jumperclient/node_modules/e131/lib/e131/rootlayer.js:63:20)

I only required library:
var e131 = require('e131');

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.