Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ This node can be used to read one or multiple universes sent by sACN.

#### Parameters:

| Parameter | Description | Possible Values | Default Value | Mandatory |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------- | --------- |
| universe | The universe that is meant to be observed. | `\d+` (`1` to `63999`) | `1` | yes |
| mode | Defines whether the node returns the values of every read sACN package (passthrough mode), or merged values using HTP or LTP. | `passthrough`, `htp`, `ltp` | `htp` | yes |
| output | Defines whether the node sends only changed values or the whole universe. | `full`, `changes` | `full` | yes |
| trigger | Controls when a message is emitted: only on change, on every received packet, or on change plus a cyclic keepalive re-emit. | `changes`, `always`, `interval` | `changes` | yes |
| interval | Keepalive interval in milliseconds for the `interval` trigger; the full universe is re-emitted when no change arrives in time. | `\d+` | `1000` | no |
| clearOnUniverseChange | When the observed universe is switched at runtime, emit a full universe of zeros until real data for the new universe arrives. | `true`, `false` | `false` | no |
| values | Emit channel values as a percentage (0–100) or as raw DMX values (0–255). | `percent`, `absolute` | `percent` | yes |
| IP-address | IP-Address of the network-interface that should be used for reading from sACN. | `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\` (_any valid ip-address_) | _empty_ | no |
| port | The network port which should be used for reading sACN. | `\d+` | _empty_ (defaults to `5568`) | no |
| Parameter | Description | Possible Values | Default Value | Mandatory |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------- | --------- |
| universe | The universe that is meant to be observed. | `\d+` (`1` to `63999`) | `1` | yes |
| mode | Defines whether the node returns the values of every read sACN package (passthrough mode), or merged values using HTP or LTP. | `passthrough`, `htp`, `ltp` | `htp` | yes |
| output | Defines whether the node sends only changed values or the whole universe. | `full`, `changes` | `full` | yes |
| trigger | Controls when a message is emitted: only on change, on every received packet, or on change plus a cyclic keepalive re-emit. | `changes`, `always`, `interval` | `changes` | yes |
| interval | Keepalive interval in milliseconds for the `interval` trigger; the full universe is re-emitted when no change arrives in time. | `\d+` | `1000` | no |
| clearOnUniverseChange | When the observed universe is switched at runtime, emit a full universe of zeros until real data for the new universe arrives. | `true`, `false` | `false` | no |
| values | Emit channel values as a percentage (0–100) or as raw DMX values (0–255). | `percent`, `absolute` | `percent` | yes |
| IP-address | IP-Address of the network-interface that should be used for reading from sACN. | `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\` (_any valid ip-address_) | _empty_ | no |
| port | The network port which should be used for reading sACN. | `\d+` | _empty_ (defaults to `5568`) | no |

#### Input:

Expand Down Expand Up @@ -69,16 +69,16 @@ This node can be used to send one universe using sACN.

#### Parameters:

| Parameter | Description | Possible Values | Default Value | Mandatory |
| ----------- | ------------------------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------- | --------- |
| universe | The universe that is meant to be observed. | `\d+` (`1` to `63999`) | `1` | yes |
| source-name | The name for the sACN-sender that should be displayed within the network. | _any string below 50 characters_ | `Node-RED` | yes |
| speed | Defines the frequency for sending sACN-packages | `once (0Hz)`, `24Hz`, `27Hz`, `30Hz`, `40Hz`, `44Hz` | `0Hz` | yes |
| priority | The priority that should be used for the sACN-sender. | `\d+` (`1` to `200`) | `100` | yes |
| values | Interpret the payload as a percentage (0–100) or as raw DMX values (0–255). | `percent`, `absolute` | `percent` | yes |
| blank-on-stop | Send an all-zero frame before closing so receivers go dark on stop. | `true`, `false` | `false` | no |
| IP-address | IP-Address of the network-interface that should be used for sending sACN. | `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\` (_any valid ip-address_) | _empty_ | no |
| port | The network port which should be used for reading sACN. | `\d+` | _empty_ (defaults to `5568`) | no |
| Parameter | Description | Possible Values | Default Value | Mandatory |
| ------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------- | --------- |
| universe | The universe that is meant to be observed. | `\d+` (`1` to `63999`) | `1` | yes |
| source-name | The name for the sACN-sender that should be displayed within the network. | _any string below 50 characters_ | `Node-RED` | yes |
| speed | Defines the frequency for sending sACN-packages | `once (0Hz)`, `24Hz`, `27Hz`, `30Hz`, `40Hz`, `44Hz` | `0Hz` | yes |
| priority | The priority that should be used for the sACN-sender. | `\d+` (`1` to `200`) | `100` | yes |
| values | Interpret the payload as a percentage (0–100) or as raw DMX values (0–255). | `percent`, `absolute` | `percent` | yes |
| blank-on-stop | Send an all-zero frame before closing so receivers go dark on stop. | `true`, `false` | `false` | no |
| IP-address | IP-Address of the network-interface that should be used for sending sACN. | `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\` (_any valid ip-address_) | _empty_ | no |
| port | The network port which should be used for reading sACN. | `\d+` | _empty_ (defaults to `5568`) | no |

#### Expected input:

Expand Down
7 changes: 6 additions & 1 deletion build.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@ function buildNodeForm(node, source, target) {

const initJSLines = initJS.split("\n");
html.push('<script type="text/javascript">');
// wrap in an IIFE so top-level declarations (e.g. `const def`, helper functions)
// stay local; multiple node editor scripts share one global scope and would
// otherwise collide ("Identifier 'def' has already been declared").
html.push(" (function () {");
initJSLines.forEach((line) => {
if (line.length > 0) {
html.push(` ${line}`);
html.push(` ${line}`);
}
});
html.push(" })();");
html.push("</script>");

html.push("");
Expand Down
212 changes: 107 additions & 105 deletions dist/nodes/sacn-in/sacn-in.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,121 +172,123 @@ <h3>References</h3>
</ul>
</script>
<script type="text/javascript">
function populateInterfaceOptions() {
const list = document.getElementById("node-input-interface-options");
if (!list) {
return;
}
$.getJSON("sacn/interfaces", (interfaces) => {
list.replaceChildren();
interfaces.forEach((iface) => {
const option = document.createElement("option");
option.value = iface.address;
option.label = `${iface.name} (${iface.address})`;
list.appendChild(option);
(function () {
function populateInterfaceOptions() {
const list = document.getElementById("node-input-interface-options");
if (!list) {
return;
}
$.getJSON("sacn/interfaces", (interfaces) => {
list.replaceChildren();
interfaces.forEach((iface) => {
const option = document.createElement("option");
option.value = iface.address;
option.label = `${iface.name} (${iface.address})`;
list.appendChild(option);
});
});
});
}
function toInt(value) {
if (typeof value === "number") {
return value;
}
if (typeof value === "string") {
return parseInt(value, 10);
function toInt(value) {
if (typeof value === "number") {
return value;
}
if (typeof value === "string") {
return parseInt(value, 10);
}
return NaN;
}
return NaN;
}
function isValidInterface(value) {
if (typeof value !== "string" || value === "") {
return true;
function isValidInterface(value) {
if (typeof value !== "string" || value === "") {
return true;
}
return /^(\d{1,3}\.){3}\d{1,3}$/.test(value);
}
return /^(\d{1,3}\.){3}\d{1,3}$/.test(value);
}
function isValidUniverse(value) {
const n = toInt(value);
return !isNaN(n) && n >= 1 && n <= 63999;
}
function isValidPort(value) {
if (value === undefined || value === null || value === "") {
return true;
function isValidUniverse(value) {
const n = toInt(value);
return !isNaN(n) && n >= 1 && n <= 63999;
}
const n = toInt(value);
return !isNaN(n) && n >= 1 && n <= 65535;
}
const def = {
category: "sACN",
color: "#dcc515",
defaults: {
name: {
value: "",
},
universe: {
value: 1,
required: true,
validate: function (v) {
return isValidUniverse(v);
function isValidPort(value) {
if (value === undefined || value === null || value === "") {
return true;
}
const n = toInt(value);
return !isNaN(n) && n >= 1 && n <= 65535;
}
const def = {
category: "sACN",
color: "#dcc515",
defaults: {
name: {
value: "",
},
},
port: {
value: undefined,
required: false,
validate: function (v) {
return isValidPort(v);
universe: {
value: 1,
required: true,
validate: function (v) {
return isValidUniverse(v);
},
},
},
interface: {
value: "",
required: false,
validate: function (v) {
return isValidInterface(v);
port: {
value: undefined,
required: false,
validate: function (v) {
return isValidPort(v);
},
},
interface: {
value: "",
required: false,
validate: function (v) {
return isValidInterface(v);
},
},
mode: {
value: "htp",
required: true,
},
output: {
value: "full",
required: true,
},
trigger: {
value: "changes",
required: true,
},
interval: {
value: 1000,
required: true,
},
clearOnUniverseChange: {
value: false,
},
values: {
value: "percent",
required: true,
},
},
mode: {
value: "htp",
required: true,
},
output: {
value: "full",
required: true,
},
trigger: {
value: "changes",
required: true,
},
interval: {
value: 1000,
required: true,
inputs: 1,
outputs: 1,
paletteLabel: "sACN in",
icon: "sacn-in.svg",
label: function () {
return this.name || `sACN in · U${this.universe}`;
},
clearOnUniverseChange: {
value: false,
labelStyle: function () {
return this.name ? "node_label_italic" : "";
},
values: {
value: "percent",
required: true,
oneditprepare: function () {
const select = document.getElementById("node-input-trigger");
const row = document.getElementById("row-interval");
const toggleInterval = () => {
if (row) {
row.style.display = select?.value === "interval" ? "" : "none";
}
};
select?.addEventListener("change", toggleInterval);
toggleInterval();
populateInterfaceOptions();
},
},
inputs: 1,
outputs: 1,
paletteLabel: "sACN in",
icon: "sacn-in.svg",
label: function () {
return this.name || `sACN in · U${this.universe}`;
},
labelStyle: function () {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function () {
const select = document.getElementById("node-input-trigger");
const row = document.getElementById("row-interval");
const toggleInterval = () => {
if (row) {
row.style.display = select?.value === "interval" ? "" : "none";
}
};
select?.addEventListener("change", toggleInterval);
toggleInterval();
populateInterfaceOptions();
},
};
RED.nodes.registerType("sacn-in", def);
};
RED.nodes.registerType("sacn-in", def);
})();
</script>
Loading
Loading