1
0
mirror of https://github.com/node-red/node-red-nodes.git synced 2023-10-10 13:36:58 +02:00

Moved all nodes into one common .js file & .html file pair

This commit is contained in:
Maxwell Hadley 2014-02-27 19:56:31 +00:00
parent f0ea85570f
commit 40b49c2944
4 changed files with 230 additions and 272 deletions

View File

@ -1,184 +0,0 @@
<!--
Copyright 2014 Maxwell R Hadley
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Edit dialog for analogue-in -->
<script type="text/x-red" data-template-name="analog-in">
<div class="form-row">
<label for="node-input-pin"><i class="icon-asterisk"></i>Input pin</label>
<select type="text" id="node-input-pin" style="width: 150px;">
<option value="">select pin</option>
<option value="P9_39">AIN0 (P9 pin 39)</option>
<option value="P9_40">AIN1 (P9 pin 40)</option>
<option value="P9_37">AIN2 (P9 pin 37)</option>
<option value="P9_38">AIN3 (P9 pin 38)</option>
<option value="P9_33">AIN4 (P9 pin 33)</option>
<option value="P9_36">AIN5 (P9 pin 36)</option>
<option value="P9_35">AIN6 (P9 pin 35)</option>
</select>
</div>
<div class="form-row">
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="Topic">
</div>
<div class="form-row">
Input Scaling
</div>
<div class="form-row">
<div id="node-input-breakpoint-container-div" style="border-radius: 5px; height: 132px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;">
<ol id="node-input-breakpoint-container" style=" list-style-type:none; margin: 0;">
</ol>
</div>
</div>
<div class="form-row">
<a href="#" class="btn btn-mini" id="node-input-add-breakpoint" style="margin-top: 4px;"><i class="icon-plus"></i> Add Breakpoint</a>
<span style="float:right; margin-top:4px">
<input type="checkbox" id="node-input-averaging" style="display:inline-block; width:auto; vertical-align:top;"> Averaging&nbsp;
</span>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<!-- Help text for analogue-in -->
<script type="text/x-red" data-help-name="analog-in">
<p>
Analogue input for the Beaglebone Black. Reads an analogue pin when triggered by
a message.
</p>
<p>The output message topic is the node topic: the output message value is the
scaled analogue input or NaN if a read error occurs.
</p>
<p>
Simple linear scaling is defined by setting the output values required for input
values of 0 and 1. You can apply more complicated scaling, e.g. for sensor linearisation,
by defining breakpoints at intermediate input values, with the desired output for
each. Values between breakpoints are linearly interpolated.
</p>
<p>
To reduce the effect of noise, enable averaging. This will read the input pin
voltage ten times in rapid succession for each input message and output the mean value.
</p>
</script>
<!-- Register analogue-in node -->
<script type="text/javascript">
RED.nodes.registerType('analog-in', {
category: 'advanced-input', // the palette category
color:"#c6dbef",
defaults: { // defines the editable properties of the node
name: { value:"" }, // along with default values.
topic: { value:"", required:true },
pin: { value:"", required:true },
breakpoints: { value:[{input:0.0, output:0.0, mutable:false}, {input:1.0, output:1.0, mutable:false}] },
averaging: { value:false, required:true }
},
inputs:1, // set the number of inputs - only 0 or 1
outputs:1, // set the number of outputs - 0 to n
icon: "arrow-in.png", // set the icon (held in public/icons)
label: function() { // sets the default label contents
return this.name || "analog-in: " + this.pin;
},
labelStyle: function() { // sets the class to apply to the label
return this.name ? "node_label_italic" : "";
},
oneditprepare: function () {
function generateBreakpoint(breakpoint, insert) {
var container = $('<li/>', {style:"margin:0; padding:4px; padding-left 10px;"});
var row = $('<div/>').appendTo(container);
var breakpointField = $('<span/>').appendTo(row);
var inputValueField = $('<input/>',
{disabled:"", class:"node-input-breakpoint-input-value", type:"text", style:"margin-left:5px; margin-right:2px; width:36%;"}).appendTo(breakpointField);
if (breakpoint.mutable) {
inputValueField.removeAttr("disabled");
}
breakpointField.append(" => ");
var outputValueField = $('<input/>',
{class:"node-input-breakpoint-output-value", type:"text", style:"margin-left:0px; width:36%;"}).appendTo(breakpointField);
var finalSpan = $('<span/>', {style:"float:right; margin-top:3px; margin-right:10px;"}).appendTo(row);
var mutableFlag = $('<span/>', {class:"node-input-breakpoint-mutable", style:"display:hide;"}).appendTo(row);
if (breakpoint.mutable) {
mutableFlag.attr("mutable", "true");
var deleteButton = $('<a/>', {href:"#", class:"btn btn-mini", style:"margin-left: 5px;"}).appendTo(finalSpan);
$('<i/>', {class:"icon-remove"}).appendTo(deleteButton);
deleteButton.click(function() {
container.css({"background":"#fee"});
container.fadeOut(300, function() {
$(this).remove();
});
});
} else {
mutableFlag.attr("mutable", "false");
}
if (insert === true) {
var last = $("#node-input-breakpoint-container").children().last();
var prev = last.prev();
inputValueField.val((Number(last.find(".node-input-breakpoint-input-value").val()) +
Number(prev.find(".node-input-breakpoint-input-value").val()))/2);
outputValueField.val((Number(last.find(".node-input-breakpoint-output-value").val()) +
Number(prev.find(".node-input-breakpoint-output-value").val()))/2);
last.before(container);
} else {
inputValueField.val(breakpoint.input);
outputValueField.val(breakpoint.output);
$("#node-input-breakpoint-container").append(container);
}
}
$("#node-input-add-breakpoint").click(function () {
generateBreakpoint({input:0, output:0, mutable:true}, true);
$("#node-input-breakpoint-container-div").scrollTop($("#node-input-breakpoint-container-div").get(0).scrollHeight);
});
for (var i = 0; i < this.breakpoints.length; i++) {
var breakpoint = this.breakpoints[i];
generateBreakpoint(breakpoint, false);
}
// Handle resizing the Input Scaling div when the dialog is resized - this isn't quite right!
function switchDialogResize(ev, ui) {
$("#node-input-breakpoint-container-div").css("height", (ui.size.height - 299) + "px");
};
$("#dialog").on("dialogresize", switchDialogResize);
$("#dialog").one("dialogopen", function (ev) {
var size = $("#dialog").dialog('option', 'sizeCache-switch');
if (size) {
switchDialogResize(null, { size:size });
}
});
$("#dialog").one("dialogclose", function(ev, ui) {
$("#dialog").off("dialogresize", switchDialogResize);
});
},
oneditsave: function() {
var breakpoints = $("#node-input-breakpoint-container").children();
var node = this;
node.breakpoints = [];
breakpoints.each(function (i) {
var breakpoint = $(this);
var r = {};
r.input = Number(breakpoint.find(".node-input-breakpoint-input-value").val());
r.output = Number(breakpoint.find(".node-input-breakpoint-output-value").val());
r.mutable = breakpoint.find(".node-input-breakpoint-mutable").attr("mutable") == "true";
node.breakpoints.push(r);
});
node.breakpoints = node.breakpoints.sort(function (a, b) { return a.input - b.input; });
}
});
</script>

View File

@ -1,84 +0,0 @@
/**
* Copyright 2014 Maxwell R Hadley
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
// Require main module
var RED = require(process.env.NODE_RED_HOME+"/red/red");
// Require bonescript
try {
var bonescript = require("bonescript");
} catch (err) {
require("util").log("[144-analog-in] Error: cannot find module 'bonescript'");
}
// Node constructor for analogue-in
function AnalogInputNode(n) {
// Create a RED node
RED.nodes.createNode(this, n);
// Store local copies of the node configuration (as defined in the .html)
this.topic = n.topic;
this.pin = n.pin;
this.breakpoints = n.breakpoints;
this.averaging = n.averaging;
if (this.averaging) {
this.averages = 10;
} else {
this.averages = 1;
}
// Define 'node' to allow us to access 'this' from within callbacks
var node = this;
// Variables used for input averaging
var sum; // accumulates the input readings to be averaged
var count; // keep track of the number of measurements made
// The callback function for analogRead. Accumulates the required number of
// measurements, then divides the total number, applies output scaling and
// sends the result
var analogReadCallback = function (x) {
sum = sum + x.value;
count = count - 1;
if (count > 0) {
bonescript.analogRead(node.pin, analogReadCallback);
} else {
var msg = {};
msg.topic = node.topic;
sum = sum/node.averages;
// i is the index of the first breakpoint where the 'input' value is strictly
// greater than the measurement (note: a measurement can never be == 1)
var i = node.breakpoints.map(function (breakpoint) { return sum >= breakpoint.input; }).indexOf(false);
msg.payload = node.breakpoints[i-1].output + (node.breakpoints[i].output - node.breakpoints[i-1].output) *
(sum - node.breakpoints[i-1].input)/(node.breakpoints[i].input - node.breakpoints[i-1].input);
node.send(msg);
}
};
// If we have a valid pin, set the input event handler to Bonescript's analogRead
if (["P9_39", "P9_40", "P9_37", "P9_38", "P9_33", "P9_36", "P9_35"].indexOf(node.pin) >= 0) {
node.on("input", function (msg) {
sum = 0;
count = node.averages;
bonescript.analogRead(node.pin, analogReadCallback);
});
} else {
node.error("Unconfigured input pin");
}
}
// Register the node by name. This must be called before overriding any of the Node functions.
RED.nodes.registerType("analog-in", AnalogInputNode);

View File

@ -14,6 +14,175 @@
limitations under the License.
-->
<!-- Edit dialog for analogue-in -->
<script type="text/x-red" data-template-name="analog-in">
<div class="form-row">
<label for="node-input-pin"><i class="icon-asterisk"></i>Input pin</label>
<select type="text" id="node-input-pin" style="width: 150px;">
<option value="">select pin</option>
<option value="P9_39">AIN0 (P9 pin 39)</option>
<option value="P9_40">AIN1 (P9 pin 40)</option>
<option value="P9_37">AIN2 (P9 pin 37)</option>
<option value="P9_38">AIN3 (P9 pin 38)</option>
<option value="P9_33">AIN4 (P9 pin 33)</option>
<option value="P9_36">AIN5 (P9 pin 36)</option>
<option value="P9_35">AIN6 (P9 pin 35)</option>
</select>
</div>
<div class="form-row">
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="Topic">
</div>
<div class="form-row">
Input Scaling
</div>
<div class="form-row">
<div id="node-input-breakpoint-container-div" style="border-radius: 5px; height: 132px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;">
<ol id="node-input-breakpoint-container" style=" list-style-type:none; margin: 0;">
</ol>
</div>
</div>
<div class="form-row">
<a href="#" class="btn btn-mini" id="node-input-add-breakpoint" style="margin-top: 4px;"><i class="icon-plus"></i> Add Breakpoint</a>
<span style="float:right; margin-top:4px">
<input type="checkbox" id="node-input-averaging" style="display:inline-block; width:auto; vertical-align:top;"> Averaging&nbsp;
</span>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<!-- Help text for analogue-in -->
<script type="text/x-red" data-help-name="analog-in">
<p>
Analogue input for the Beaglebone Black. Reads an analogue pin when triggered by
a message.
</p>
<p>The output message topic is the node topic: the output message value is the
scaled analogue input or NaN if a read error occurs.
</p>
<p>
Simple linear scaling is defined by setting the output values required for input
values of 0 and 1. You can apply more complicated scaling, e.g. for sensor linearisation,
by defining breakpoints at intermediate input values, with the desired output for
each. Values between breakpoints are linearly interpolated.
</p>
<p>
To reduce the effect of noise, enable averaging. This will read the input pin
voltage ten times in rapid succession for each input message and output the mean value.
</p>
</script>
<!-- Register analogue-in node -->
<script type="text/javascript">
RED.nodes.registerType('analog-in', {
category: 'advanced-input', // the palette category
color:"#c6dbef",
defaults: { // defines the editable properties of the node
name: { value:"" }, // along with default values.
topic: { value:"", required:true },
pin: { value:"", required:true },
breakpoints: { value:[{input:0.0, output:0.0, mutable:false}, {input:1.0, output:1.0, mutable:false}] },
averaging: { value:false, required:true }
},
inputs:1, // set the number of inputs - only 0 or 1
outputs:1, // set the number of outputs - 0 to n
icon: "arrow-in.png", // set the icon (held in public/icons)
label: function() { // sets the default label contents
return this.name || "analog-in: " + this.pin;
},
labelStyle: function() { // sets the class to apply to the label
return this.name ? "node_label_italic" : "";
},
oneditprepare: function () {
function generateBreakpoint(breakpoint, insert) {
var container = $('<li/>', {style:"margin:0; padding:4px; padding-left 10px;"});
var row = $('<div/>').appendTo(container);
var breakpointField = $('<span/>').appendTo(row);
var inputValueField = $('<input/>',
{disabled:"", class:"node-input-breakpoint-input-value", type:"text", style:"margin-left:5px; margin-right:2px; width:36%;"}).appendTo(breakpointField);
if (breakpoint.mutable) {
inputValueField.removeAttr("disabled");
}
breakpointField.append(" => ");
var outputValueField = $('<input/>',
{class:"node-input-breakpoint-output-value", type:"text", style:"margin-left:0px; width:36%;"}).appendTo(breakpointField);
var finalSpan = $('<span/>', {style:"float:right; margin-top:3px; margin-right:10px;"}).appendTo(row);
var mutableFlag = $('<span/>', {class:"node-input-breakpoint-mutable", style:"display:hide;"}).appendTo(row);
if (breakpoint.mutable) {
mutableFlag.attr("mutable", "true");
var deleteButton = $('<a/>', {href:"#", class:"btn btn-mini", style:"margin-left: 5px;"}).appendTo(finalSpan);
$('<i/>', {class:"icon-remove"}).appendTo(deleteButton);
deleteButton.click(function() {
container.css({"background":"#fee"});
container.fadeOut(300, function() {
$(this).remove();
});
});
} else {
mutableFlag.attr("mutable", "false");
}
if (insert === true) {
var last = $("#node-input-breakpoint-container").children().last();
var prev = last.prev();
inputValueField.val((Number(last.find(".node-input-breakpoint-input-value").val()) +
Number(prev.find(".node-input-breakpoint-input-value").val()))/2);
outputValueField.val((Number(last.find(".node-input-breakpoint-output-value").val()) +
Number(prev.find(".node-input-breakpoint-output-value").val()))/2);
last.before(container);
} else {
inputValueField.val(breakpoint.input);
outputValueField.val(breakpoint.output);
$("#node-input-breakpoint-container").append(container);
}
}
$("#node-input-add-breakpoint").click(function () {
generateBreakpoint({input:0, output:0, mutable:true}, true);
$("#node-input-breakpoint-container-div").scrollTop($("#node-input-breakpoint-container-div").get(0).scrollHeight);
});
for (var i = 0; i < this.breakpoints.length; i++) {
var breakpoint = this.breakpoints[i];
generateBreakpoint(breakpoint, false);
}
// Handle resizing the Input Scaling div when the dialog is resized - this isn't quite right!
function switchDialogResize(ev, ui) {
$("#node-input-breakpoint-container-div").css("height", (ui.size.height - 299) + "px");
};
$("#dialog").on("dialogresize", switchDialogResize);
$("#dialog").one("dialogopen", function (ev) {
var size = $("#dialog").dialog('option', 'sizeCache-switch');
if (size) {
switchDialogResize(null, { size:size });
}
});
$("#dialog").one("dialogclose", function(ev, ui) {
$("#dialog").off("dialogresize", switchDialogResize);
});
},
oneditsave: function() {
var breakpoints = $("#node-input-breakpoint-container").children();
var node = this;
node.breakpoints = [];
breakpoints.each(function (i) {
var breakpoint = $(this);
var r = {};
r.input = Number(breakpoint.find(".node-input-breakpoint-input-value").val());
r.output = Number(breakpoint.find(".node-input-breakpoint-output-value").val());
r.mutable = breakpoint.find(".node-input-breakpoint-mutable").attr("mutable") == "true";
node.breakpoints.push(r);
});
node.breakpoints = node.breakpoints.sort(function (a, b) { return a.input - b.input; });
}
});
</script>
<!-- Edit dialog for discrete-in -->
<script type="text/x-red" data-template-name="discrete-in">
<div class="form-row">
@ -107,7 +276,7 @@ press. When using buttons or switches, enable debouncing to improve reliability.
</p>
</script>
<!-- Register discrete-in -->
<!-- Register discrete-in node -->
<script type="text/javascript">
RED.nodes.registerType('discrete-in', {
category: 'advanced-input', // the palette category
@ -218,7 +387,7 @@ any other input message will reset it to zero.
</p>
</script>
<!-- Register pulse-in -->
<!-- Register pulse-in node -->
<script type="text/javascript">
RED.nodes.registerType('pulse-in', {
category: 'advanced-input', // the palette category
@ -329,7 +498,7 @@ the Inverting property is not applied to this value.
</p>
</script>
<!-- Register discrete-out -->
<!-- Register discrete-out node -->
<script type="text/javascript">
RED.nodes.registerType('discrete-out', {
category: 'advanced-input', // the palette category
@ -441,7 +610,7 @@ the pin changes state: its payload is the new state (0 or 1).
</p>
</script>
<!-- Register pulse-out -->
<!-- Register pulse-out node -->
<script type="text/javascript">
RED.nodes.registerType('pulse-out', {
category: 'advanced-input', // the palette category

View File

@ -24,6 +24,62 @@ try {
require("util").log("[145-digital-in] Error: cannot find module 'bonescript'");
}
// Node constructor for analogue-in
function AnalogInputNode(n) {
// Create a RED node
RED.nodes.createNode(this, n);
// Store local copies of the node configuration (as defined in the .html)
this.topic = n.topic;
this.pin = n.pin;
this.breakpoints = n.breakpoints;
this.averaging = n.averaging;
if (this.averaging) {
this.averages = 10;
} else {
this.averages = 1;
}
// Define 'node' to allow us to access 'this' from within callbacks
var node = this;
// Variables used for input averaging
var sum; // accumulates the input readings to be averaged
var count; // keep track of the number of measurements made
// The callback function for analogRead. Accumulates the required number of
// measurements, then divides the total number, applies output scaling and
// sends the result
var analogReadCallback = function (x) {
sum = sum + x.value;
count = count - 1;
if (count > 0) {
bonescript.analogRead(node.pin, analogReadCallback);
} else {
var msg = {};
msg.topic = node.topic;
sum = sum/node.averages;
// i is the index of the first breakpoint where the 'input' value is strictly
// greater than the measurement (note: a measurement can never be == 1)
var i = node.breakpoints.map(function (breakpoint) { return sum >= breakpoint.input; }).indexOf(false);
msg.payload = node.breakpoints[i-1].output + (node.breakpoints[i].output - node.breakpoints[i-1].output) *
(sum - node.breakpoints[i-1].input)/(node.breakpoints[i].input - node.breakpoints[i-1].input);
node.send(msg);
}
};
// If we have a valid pin, set the input event handler to Bonescript's analogRead
if (["P9_39", "P9_40", "P9_37", "P9_38", "P9_33", "P9_36", "P9_35"].indexOf(node.pin) >= 0) {
node.on("input", function (msg) {
sum = 0;
count = node.averages;
bonescript.analogRead(node.pin, analogReadCallback);
});
} else {
node.error("Unconfigured input pin");
}
}
// Node constructor for discrete-in
function DiscreteInputNode(n) {
RED.nodes.createNode(this, n);
@ -415,6 +471,7 @@ function PulseOutputNode(n) {
}
// Register the nodes by name. This must be called before overriding any of the Node functions.
RED.nodes.registerType("analog-in", AnalogInputNode);
RED.nodes.registerType("discrete-in", DiscreteInputNode);
RED.nodes.registerType("pulse-in", PulseInputNode);
RED.nodes.registerType("discrete-out", DiscreteOutputNode);