subscribe and interval nodes added
This commit is contained in:
40
nodes/xilica-interval.html
Normal file
40
nodes/xilica-interval.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('xilica-interval', {
|
||||
category: 'Xilica',
|
||||
color: '#D8E7FF',
|
||||
defaults: {
|
||||
name: { value: "" },
|
||||
interval: { value: 100 }
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "font-awesome/fa-plug",
|
||||
label: function () {
|
||||
if (this.name) {
|
||||
return this.name;
|
||||
}
|
||||
if (this.interval) {
|
||||
return "xilica interval " + this.interval + "ms";
|
||||
}
|
||||
return "xilica interval";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="xilica-interval">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name">Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-interval">Interval (ms)</label>
|
||||
<input type="number" id="node-input-interval" min="10" max="60000">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xilica-interval">
|
||||
<p>Builds an <code>INTERVAL</code> command for a Xilica Solaro processor.</p>
|
||||
<p>On each input message, the node sets <code>msg.payload</code> to <code>INTERVAL <value></code>. Wire the output into a <code>xilica-command</code> node to send it over TCP.</p>
|
||||
<p>You can override the configured interval by setting <code>msg.interval</code> on the incoming message.</p>
|
||||
</script>
|
||||
|
||||
33
nodes/xilica-interval.js
Normal file
33
nodes/xilica-interval.js
Normal file
@@ -0,0 +1,33 @@
|
||||
module.exports = function (RED) {
|
||||
function XilicaInterval(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
const node = this;
|
||||
|
||||
node.interval = parseInt(config.interval, 10) || 100;
|
||||
|
||||
node.on("input", (msg, send, done) => {
|
||||
send =
|
||||
send ||
|
||||
function () {
|
||||
node.send.apply(node, arguments);
|
||||
};
|
||||
done = done || function () {};
|
||||
|
||||
let interval = node.interval;
|
||||
if (Object.prototype.hasOwnProperty.call(msg, "interval")) {
|
||||
const v = parseInt(msg.interval, 10);
|
||||
if (!Number.isNaN(v) && v > 0) {
|
||||
interval = v;
|
||||
}
|
||||
}
|
||||
|
||||
msg.payload = "INTERVAL " + interval;
|
||||
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("xilica-interval", XilicaInterval);
|
||||
};
|
||||
|
||||
79
nodes/xilica-subscribe.html
Normal file
79
nodes/xilica-subscribe.html
Normal file
@@ -0,0 +1,79 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('xilica-subscribe', {
|
||||
category: 'Xilica',
|
||||
color: '#D8E7FF',
|
||||
defaults: {
|
||||
name: { value: "" },
|
||||
action: { value: "subscribe" },
|
||||
mode: { value: "list" },
|
||||
targets: { value: "" },
|
||||
startIndex: { value: 1 },
|
||||
endIndex: { value: 1 },
|
||||
transport: { value: "TCP" }
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "font-awesome/fa-plug",
|
||||
label: function () {
|
||||
var act = (this.action || "subscribe").toLowerCase();
|
||||
if (this.name) {
|
||||
return this.name;
|
||||
}
|
||||
return "xilica " + act;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="xilica-subscribe">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name">Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-action">Action</label>
|
||||
<select id="node-input-action">
|
||||
<option value="subscribe">Subscribe</option>
|
||||
<option value="unsubscribe">Unsubscribe</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-mode">Mode</label>
|
||||
<select id="node-input-mode">
|
||||
<option value="list">Explicit list</option>
|
||||
<option value="startsWith">Starts with</option>
|
||||
<option value="endsWith">Ends with</option>
|
||||
<option value="startsAndEnds">Starts with and ends with</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-targets">Targets</label>
|
||||
<textarea id="node-input-targets" rows="5" style="width: 100%;"></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-startIndex">Start index</label>
|
||||
<input type="number" id="node-input-startIndex" min="0">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-endIndex">End index</label>
|
||||
<input type="number" id="node-input-endIndex" min="0">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-transport">Transport</label>
|
||||
<input type="text" id="node-input-transport" placeholder="TCP">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xilica-subscribe">
|
||||
<p>Builds <code>SUBSCRIBE</code> or <code>UNSUBSCRIBE</code> commands for a Xilica Solaro processor.</p>
|
||||
<p>On each input message, the node sets <code>msg.payload</code> to one or more commands separated by carriage returns. Wire the output into a <code>xilica-command</code> node to send them over TCP.</p>
|
||||
<p><strong>Action</strong> selects whether to generate <code>SUBSCRIBE</code> or <code>UNSUBSCRIBE</code> commands.</p>
|
||||
<p><strong>Mode</strong> controls how the Targets field is interpreted:</p>
|
||||
<ul>
|
||||
<li><strong>Explicit list</strong>: each non-empty line in Targets is used as a full control name (e.g. <code>MASTER_GAIN</code>).</li>
|
||||
<li><strong>Starts with</strong>: each line in Targets is treated as a prefix (e.g. <code>CH</code>), and Start/End index define the numeric range (e.g. 1–48 → <code>CH1</code>…<code>CH48</code>).</li>
|
||||
<li><strong>Ends with</strong>: each line in Targets is treated as a suffix (e.g. <code>_OUT</code>), and Start/End index define the numeric range (e.g. 1–4 → <code>1_OUT</code>…<code>4_OUT</code>).</li>
|
||||
<li><strong>Starts with and ends with</strong>: each line in Targets is interpreted as <code>prefix|suffix</code> (for example <code>CH|OUT</code>), and Start/End index define the numeric range (e.g. 4–28 → <code>CH4OUT</code>…<code>CH28OUT</code>).</li>
|
||||
</ul>
|
||||
<p>The Transport field controls the subscription transport string, typically <code>TCP</code>. The node generates commands like <code>SUBSCRIBE CH1 "TCP"</code>.</p>
|
||||
</script>
|
||||
|
||||
153
nodes/xilica-subscribe.js
Normal file
153
nodes/xilica-subscribe.js
Normal file
@@ -0,0 +1,153 @@
|
||||
module.exports = function (RED) {
|
||||
function buildNamesFromList(targets) {
|
||||
return targets
|
||||
.split(/\r?\n/)
|
||||
.map((l) => l.trim())
|
||||
.filter((l) => l.length > 0);
|
||||
}
|
||||
|
||||
function buildNamesStartsWith(targets, startIndex, endIndex) {
|
||||
const prefixes = buildNamesFromList(targets);
|
||||
const names = [];
|
||||
if (startIndex > endIndex) {
|
||||
const tmp = startIndex;
|
||||
startIndex = endIndex;
|
||||
endIndex = tmp;
|
||||
}
|
||||
prefixes.forEach((prefix) => {
|
||||
for (let i = startIndex; i <= endIndex; i += 1) {
|
||||
names.push(prefix + i);
|
||||
}
|
||||
});
|
||||
return names;
|
||||
}
|
||||
|
||||
function buildNamesEndsWith(targets, startIndex, endIndex) {
|
||||
const suffixes = buildNamesFromList(targets);
|
||||
const names = [];
|
||||
if (startIndex > endIndex) {
|
||||
const tmp = startIndex;
|
||||
startIndex = endIndex;
|
||||
endIndex = tmp;
|
||||
}
|
||||
suffixes.forEach((suffix) => {
|
||||
for (let i = startIndex; i <= endIndex; i += 1) {
|
||||
names.push(String(i) + suffix);
|
||||
}
|
||||
});
|
||||
return names;
|
||||
}
|
||||
|
||||
function buildNamesStartsAndEnds(targets, startIndex, endIndex) {
|
||||
const patterns = buildNamesFromList(targets);
|
||||
const names = [];
|
||||
if (startIndex > endIndex) {
|
||||
const tmp = startIndex;
|
||||
startIndex = endIndex;
|
||||
endIndex = tmp;
|
||||
}
|
||||
patterns.forEach((pattern) => {
|
||||
const parts = pattern.split("|");
|
||||
const prefix = (parts[0] || "").trim();
|
||||
const suffix = (parts[1] || "").trim();
|
||||
if (!prefix && !suffix) {
|
||||
return;
|
||||
}
|
||||
for (let i = startIndex; i <= endIndex; i += 1) {
|
||||
names.push(prefix + i + suffix);
|
||||
}
|
||||
});
|
||||
return names;
|
||||
}
|
||||
|
||||
function buildControlNames(mode, targets, startIndex, endIndex) {
|
||||
if (mode === "startsWith") {
|
||||
return buildNamesStartsWith(targets, startIndex, endIndex);
|
||||
}
|
||||
if (mode === "endsWith") {
|
||||
return buildNamesEndsWith(targets, startIndex, endIndex);
|
||||
}
|
||||
if (mode === "startsAndEnds") {
|
||||
return buildNamesStartsAndEnds(targets, startIndex, endIndex);
|
||||
}
|
||||
return buildNamesFromList(targets);
|
||||
}
|
||||
|
||||
function normaliseAction(action) {
|
||||
const a = (action || "").toString().toLowerCase();
|
||||
if (a === "unsubscribe" || a === "unsub") {
|
||||
return "UNSUBSCRIBE";
|
||||
}
|
||||
return "SUBSCRIBE";
|
||||
}
|
||||
|
||||
function XilicaSubscribe(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
const node = this;
|
||||
|
||||
node.action = config.action || "subscribe";
|
||||
node.mode = config.mode || "list";
|
||||
node.targets = config.targets || "";
|
||||
node.startIndex = parseInt(config.startIndex, 10) || 1;
|
||||
node.endIndex = parseInt(config.endIndex, 10) || node.startIndex;
|
||||
node.transport = config.transport || "TCP";
|
||||
|
||||
node.on("input", (msg, send, done) => {
|
||||
send =
|
||||
send ||
|
||||
function () {
|
||||
node.send.apply(node, arguments);
|
||||
};
|
||||
done = done || function () {};
|
||||
|
||||
const action = normaliseAction(msg.action || node.action);
|
||||
const mode = (msg.mode || node.mode || "list").toString();
|
||||
|
||||
const targets =
|
||||
typeof msg.targets === "string" && msg.targets.trim().length
|
||||
? msg.targets
|
||||
: node.targets;
|
||||
|
||||
let startIndex = node.startIndex;
|
||||
let endIndex = node.endIndex;
|
||||
if (Object.prototype.hasOwnProperty.call(msg, "startIndex")) {
|
||||
const v = parseInt(msg.startIndex, 10);
|
||||
if (!Number.isNaN(v)) {
|
||||
startIndex = v;
|
||||
}
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(msg, "endIndex")) {
|
||||
const v = parseInt(msg.endIndex, 10);
|
||||
if (!Number.isNaN(v)) {
|
||||
endIndex = v;
|
||||
}
|
||||
}
|
||||
|
||||
const transport =
|
||||
typeof msg.transport === "string" && msg.transport.trim().length
|
||||
? msg.transport.trim()
|
||||
: node.transport;
|
||||
|
||||
const names = buildControlNames(mode, targets || "", startIndex, endIndex);
|
||||
|
||||
if (!names.length) {
|
||||
node.warn("xilica-subscribe: no targets defined");
|
||||
send(msg);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
const lines = names.map(
|
||||
(name) => action + " " + name + ' "' + transport + '"',
|
||||
);
|
||||
|
||||
msg.payload = lines.join("\r");
|
||||
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("xilica-subscribe", XilicaSubscribe);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
"nodes": {
|
||||
"xilica-ping": "nodes/xilica-ping.js",
|
||||
"xilica-connection": "nodes/xilica-connection.js",
|
||||
"xilica-command": "nodes/xilica-command.js"
|
||||
"xilica-command": "nodes/xilica-command.js",
|
||||
"xilica-interval": "nodes/xilica-interval.js",
|
||||
"xilica-subscribe": "nodes/xilica-subscribe.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user