mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b110e4de17
@ -16,13 +16,15 @@
|
|||||||
|
|
||||||
<script type="text/x-red" data-template-name="debug">
|
<script type="text/x-red" data-template-name="debug">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
<label for="node-input-complete"><i class="icon-list"></i> Output</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<select type="text" id="node-input-complete" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
|
<option value=false>Payload only</option>
|
||||||
|
<option value=true>Complete msg object</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label> </label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="checkbox" id="node-input-complete" placeholder="Complete" style="display: inline-block; width: auto; vertical-align: top;">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
<label for="node-input-complete" style="width: 70%;">Show complete msg object ?</label>
|
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -113,10 +115,16 @@
|
|||||||
|
|
||||||
var sbc = document.getElementById("debug-content");
|
var sbc = document.getElementById("debug-content");
|
||||||
|
|
||||||
|
var errornotification = null;
|
||||||
|
|
||||||
function debugConnect() {
|
function debugConnect() {
|
||||||
//console.log("debug ws connecting");
|
//console.log("debug ws connecting");
|
||||||
var ws = new WebSocket("ws://"+location.hostname+":"+location.port+document.location.pathname+"/debug");
|
var ws = new WebSocket("ws://"+location.hostname+":"+location.port+document.location.pathname+"/debug");
|
||||||
ws.onopen = function() {
|
ws.onopen = function() {
|
||||||
|
if (errornotification) {
|
||||||
|
errornotification.close();
|
||||||
|
errornotification = null;
|
||||||
|
}
|
||||||
//console.log("debug ws connected");
|
//console.log("debug ws connected");
|
||||||
}
|
}
|
||||||
ws.onmessage = function(event) {
|
ws.onmessage = function(event) {
|
||||||
@ -158,7 +166,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
ws.onclose = function() {
|
ws.onclose = function() {
|
||||||
//console.log("debug ws closed");
|
if (errornotification == null) {
|
||||||
|
errornotification = RED.notify("<b>Error</b>: Lost connection to server","error",true);
|
||||||
|
}
|
||||||
setTimeout(debugConnect,1000);
|
setTimeout(debugConnect,1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,23 +19,27 @@ var RED = require("../../red/red");
|
|||||||
var util = require("util");
|
var util = require("util");
|
||||||
var ws = require('ws');
|
var ws = require('ws');
|
||||||
var events = require("events");
|
var events = require("events");
|
||||||
|
var debuglength = RED.settings.debugMaxLength||1000;
|
||||||
|
|
||||||
function DebugNode(n) {
|
function DebugNode(n) {
|
||||||
RED.nodes.createNode(this,n);
|
RED.nodes.createNode(this,n);
|
||||||
this.name = n.name;
|
this.name = n.name;
|
||||||
this.complete = n.complete;
|
this.complete = n.complete;
|
||||||
this.active = (n.active == null)||n.active;
|
this.active = (n.active == null)||n.active;
|
||||||
|
|
||||||
this.on("input",function(msg) {
|
this.on("input",function(msg) {
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
if (msg.payload instanceof Buffer) {
|
if (msg.payload instanceof Buffer) {
|
||||||
msg.payload = "(Buffer) "+msg.payload.toString();
|
msg.payload = "(Buffer) "+msg.payload.toString();
|
||||||
}
|
}
|
||||||
if (this.complete) {
|
if (this.complete == "true") {
|
||||||
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path});
|
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path});
|
||||||
} else {
|
} else {
|
||||||
|
if (typeof msg.payload !== "undefined") {
|
||||||
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg.payload,_path:msg._path});
|
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg.payload,_path:msg._path});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,18 +50,23 @@ DebugNode.send = function(msg) {
|
|||||||
msg.msg = msg.msg.toString();
|
msg.msg = msg.msg.toString();
|
||||||
}
|
}
|
||||||
else if (typeof msg.msg === 'object') {
|
else if (typeof msg.msg === 'object') {
|
||||||
try {
|
var seen = [];
|
||||||
msg.msg = "(Object) "+JSON.stringify(msg.msg,null,1);
|
msg.msg = "(Object) " + JSON.stringify(msg.msg, function(key, value) {
|
||||||
}
|
if (typeof value === 'object' && value !== null) {
|
||||||
catch (err) {
|
if (seen.indexOf(value) !== -1) { return "[circular]"; }
|
||||||
console.log(msg.msg);
|
seen.push(value);
|
||||||
console.log(err);
|
|
||||||
msg.msg = "[Error] Can't stringify object with circular reference - see console log.";
|
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
|
}," ");
|
||||||
|
seen = null;
|
||||||
}
|
}
|
||||||
else if (typeof msg.msg === "boolean") msg.msg = "(boolean) "+msg.msg.toString();
|
else if (typeof msg.msg === "boolean") msg.msg = "(boolean) "+msg.msg.toString();
|
||||||
else if (msg.msg === 0) msg.msg = "0";
|
else if (msg.msg === 0) msg.msg = "0";
|
||||||
|
|
||||||
|
if (msg.msg.length > debuglength) {
|
||||||
|
msg.msg = msg.msg.substr(0,debuglength) +" ....";
|
||||||
|
}
|
||||||
|
|
||||||
for (var i in DebugNode.activeConnections) {
|
for (var i in DebugNode.activeConnections) {
|
||||||
var ws = DebugNode.activeConnections[i];
|
var ws = DebugNode.activeConnections[i];
|
||||||
try {
|
try {
|
||||||
|
@ -19,10 +19,16 @@
|
|||||||
<label for="node-input-name"><i class="icon-tag"></i> Comment</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Comment</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Comment">
|
<input type="text" id="node-input-name" placeholder="Comment">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-info"><i class="icon-file"></i> More</label>
|
||||||
|
<input type="hidden" id="node-input-info">
|
||||||
|
<div style="height: 250px;" class="node-text-editor" id="node-input-info-editor" ></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-tips">Tip: this isn't meant for War and Peace - but useful notes can be kept here.</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="comment">
|
<script type="text/x-red" data-help-name="comment">
|
||||||
<p>Simple comment block. More of a label really...</p>
|
<p>Simple comment block.</p>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -30,7 +36,8 @@
|
|||||||
category: 'function',
|
category: 'function',
|
||||||
color:"#ffffff",
|
color:"#ffffff",
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""}
|
name: {value:""},
|
||||||
|
info: {value:""}
|
||||||
},
|
},
|
||||||
inputs:0,
|
inputs:0,
|
||||||
outputs:0,
|
outputs:0,
|
||||||
@ -40,6 +47,39 @@
|
|||||||
},
|
},
|
||||||
labelStyle: function() {
|
labelStyle: function() {
|
||||||
return this.name?"node_label_italic":"";
|
return this.name?"node_label_italic":"";
|
||||||
|
},
|
||||||
|
oneditprepare: function() {
|
||||||
|
$( "#node-input-outputs" ).spinner({
|
||||||
|
min:1
|
||||||
|
});
|
||||||
|
function functionDialogResize(ev,ui) {
|
||||||
|
$("#node-input-info-editor").css("height",(ui.size.height-235)+"px");
|
||||||
|
};
|
||||||
|
$( "#dialog" ).on("dialogresize", functionDialogResize);
|
||||||
|
$( "#dialog" ).one("dialogopen", function(ev) {
|
||||||
|
var size = $( "#dialog" ).dialog('option','sizeCache-function');
|
||||||
|
if (size) {
|
||||||
|
functionDialogResize(null,{size:size});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$( "#dialog" ).one("dialogclose", function(ev,ui) {
|
||||||
|
var height = $( "#dialog" ).dialog('option','height');
|
||||||
|
$( "#dialog" ).off("dialogresize",functionDialogResize);
|
||||||
|
});
|
||||||
|
var that = this;
|
||||||
|
require(["orion/editor/edit"], function(edit) {
|
||||||
|
that.editor = edit({
|
||||||
|
parent:document.getElementById('node-input-info-editor'),
|
||||||
|
lang:"text",
|
||||||
|
showLinesRuler:false,
|
||||||
|
showFoldingRuler:false,
|
||||||
|
contents: $("#node-input-info").val()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
oneditsave: function() {
|
||||||
|
$("#node-input-info").val(this.editor.getText());
|
||||||
|
delete this.editor;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
126
nodes/hardware/36-rpi-gpio.html
Normal file
126
nodes/hardware/36-rpi-gpio.html
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<!--
|
||||||
|
Copyright 2013 IBM Corp.
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="rpi-gpio in">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-pin"><i class="icon-asterisk"></i> GPIO Pin</label>
|
||||||
|
<select type="text" id="node-input-pin" style="width: 150px;">
|
||||||
|
<option value="-">select pin</option>
|
||||||
|
<option value="7">7</option>
|
||||||
|
<option value="11">11</option>
|
||||||
|
<option value="12">12</option>
|
||||||
|
<option value="13">13</option>
|
||||||
|
<option value="15">15</option>
|
||||||
|
<option value="16">16</option>
|
||||||
|
<option value="18">18</option>
|
||||||
|
<option value="22">22</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-intype"><i class=" icon-resize-full"></i> Resistor?</label>
|
||||||
|
<select type="text" id="node-input-intype" style="width: 150px;">
|
||||||
|
<option value="tri">none</option>
|
||||||
|
<option value="up">pullup</option>
|
||||||
|
<option value="down">pulldown</option>
|
||||||
|
<!--<option value="tri">tristate</option>-->
|
||||||
|
</select>
|
||||||
|
</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>
|
||||||
|
<div class="form-tips">Tip: Only Digital I/O is supported - input must be 0 or 1.</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-help-name="rpi-gpio in">
|
||||||
|
<p>Raspberry Pi input node. Generates a <b>msg.payload</b> with either a 0 or 1 depending on the state of the input pin. Requires the gpio command to work.</p>
|
||||||
|
<p>You may also enable the input pullup resitor or the pulldown resistor.</p>
|
||||||
|
<p>The <b>msg.topic</b> is set to <i>pi/{the pin number}</i></p>
|
||||||
|
<p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
|
||||||
|
<p><b>Note:</b> This node currently polls the pin every 250mS. This is not ideal as it loads the cpu, and will be rewritten shortly to try to use interrupts.</p>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('rpi-gpio in',{
|
||||||
|
category: 'advanced-input',
|
||||||
|
color:"#c6dbef",
|
||||||
|
defaults: {
|
||||||
|
name: { value:"" },
|
||||||
|
intype: { value: "in" },
|
||||||
|
pin: { value:"",required:true,validate:RED.validators.number() },
|
||||||
|
},
|
||||||
|
inputs:0,
|
||||||
|
outputs:1,
|
||||||
|
icon: "rpi.png",
|
||||||
|
label: function() {
|
||||||
|
return this.name||"Pin: "+this.pin ;
|
||||||
|
},
|
||||||
|
labelStyle: function() {
|
||||||
|
return this.name?"node_label_italic":"";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="rpi-gpio out">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-pin"><i class="icon-asterisk"></i> GPIO Pin</label>
|
||||||
|
<select type="text" id="node-input-pin" style="width: 150px;">
|
||||||
|
<option value="-">select pin</option>
|
||||||
|
<option value="7">7</option>
|
||||||
|
<option value="11">11</option>
|
||||||
|
<option value="12">12</option>
|
||||||
|
<option value="13">13</option>
|
||||||
|
<option value="15">15</option>
|
||||||
|
<option value="16">16</option>
|
||||||
|
<option value="18">18</option>
|
||||||
|
<option value="22">22</option>
|
||||||
|
</select>
|
||||||
|
</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>
|
||||||
|
<div class="form-tips">Tip: Only Digital I/O is supported - input must be 0 or 1.</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-help-name="rpi-gpio out">
|
||||||
|
<p>Raspberry Pi output node. Expects a <b>msg.payload</b> with either a 0 or 1 (or true or false). Requires the gpio command to work.</p>
|
||||||
|
<p>Will set the selected physical pin high or low depending on the value passed in.</p>
|
||||||
|
<p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('rpi-gpio out',{
|
||||||
|
category: 'advanced-output',
|
||||||
|
color:"#c6dbef",
|
||||||
|
defaults: {
|
||||||
|
name: { value:"" },
|
||||||
|
pin: { value:"",required:true,validate:RED.validators.number() },
|
||||||
|
},
|
||||||
|
inputs:1,
|
||||||
|
outputs:0,
|
||||||
|
icon: "rpi.png",
|
||||||
|
align: "right",
|
||||||
|
label: function() {
|
||||||
|
return this.name||"Pin: "+this.pin;
|
||||||
|
},
|
||||||
|
labelStyle: function() {
|
||||||
|
return this.name?"node_label_italic":"";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
141
nodes/hardware/36-rpi-gpio.js
Normal file
141
nodes/hardware/36-rpi-gpio.js
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2013 IBM Corp.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var RED = require("../../red/red");
|
||||||
|
var util = require("util");
|
||||||
|
var exec = require('child_process').exec;
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
if (!fs.existsSync("/usr/local/bin/gpio")) {
|
||||||
|
exec("cat /proc/cpuinfo | grep BCM27",function(err,stdout,stderr) {
|
||||||
|
if (stdout.indexOf('BCM27') > -1) {
|
||||||
|
util.log('[36-rpi-gpio.js] Error: Cannot find Wiring-Pi "gpio" command');
|
||||||
|
}
|
||||||
|
// else not on a Pi so don't worry anyone with needless messages.
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map physical P1 pins to Gordon's Wiring-Pi Pins (as they should be V1/V2 tolerant)
|
||||||
|
var pintable = {
|
||||||
|
// Physical : WiringPi
|
||||||
|
"7":"7",
|
||||||
|
"11":"0",
|
||||||
|
"12":"1",
|
||||||
|
"13":"2",
|
||||||
|
"15":"3",
|
||||||
|
"16":"4",
|
||||||
|
"18":"5",
|
||||||
|
"22":"6"
|
||||||
|
}
|
||||||
|
var tablepin = {
|
||||||
|
// WiringPi : Physical
|
||||||
|
"7":"7",
|
||||||
|
"0":"11",
|
||||||
|
"1":"12",
|
||||||
|
"2":"13",
|
||||||
|
"3":"15",
|
||||||
|
"4":"16",
|
||||||
|
"5":"18",
|
||||||
|
"6":"22"
|
||||||
|
}
|
||||||
|
|
||||||
|
function GPIOInNode(n) {
|
||||||
|
RED.nodes.createNode(this,n);
|
||||||
|
this.buttonState = -1;
|
||||||
|
this.pin = pintable[n.pin];
|
||||||
|
this.intype = n.intype;
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
if (this.pin) {
|
||||||
|
exec("gpio mode "+node.pin+" "+node.intype, function(err,stdout,stderr) {
|
||||||
|
if (err) node.error(err);
|
||||||
|
else {
|
||||||
|
node._interval = setInterval( function() {
|
||||||
|
exec("gpio read "+node.pin, function(err,stdout,stderr) {
|
||||||
|
if (err) node.error(err);
|
||||||
|
else {
|
||||||
|
if (node.buttonState !== Number(stdout)) {
|
||||||
|
var previousState = node.buttonState;
|
||||||
|
node.buttonState = Number(stdout);
|
||||||
|
if (previousState !== -1) {
|
||||||
|
var msg = {topic:"pi/"+tablepin[node.pin], payload:node.buttonState};
|
||||||
|
node.send(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.error("Invalid GPIO pin: "+this.pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function GPIOOutNode(n) {
|
||||||
|
RED.nodes.createNode(this,n);
|
||||||
|
this.pin = pintable[n.pin];
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
if (this.pin) {
|
||||||
|
process.nextTick(function() {
|
||||||
|
exec("gpio mode "+node.pin+" out", function(err,stdout,stderr) {
|
||||||
|
if (err) node.error(err);
|
||||||
|
else {
|
||||||
|
node.on("input", function(msg) {
|
||||||
|
if (msg.payload === "true") msg.payload = true;
|
||||||
|
if (msg.payload === "false") msg.payload = false;
|
||||||
|
var out = Number(msg.payload);
|
||||||
|
if ((out == 0)|(out == 1)) {
|
||||||
|
exec("gpio write "+node.pin+" "+out, function(err,stdout,stderr) {
|
||||||
|
if (err) node.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else node.warn("Invalid input - not 0 or 1");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.error("Invalid GPIO pin: "+this.pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exec("gpio reset",function(err,stdout,stderr) {
|
||||||
|
if (err) {
|
||||||
|
util.log('[36-rpi-gpio.js] Error: "gpio reset" command failed for some reason.');
|
||||||
|
}
|
||||||
|
exec("gpio load spi",function(err,stdout,stderr) {
|
||||||
|
if (err) {
|
||||||
|
util.log('[36-rpi-gpio.js] Error: "gpio load spi" command failed for some reason.');
|
||||||
|
}
|
||||||
|
|
||||||
|
RED.nodes.registerType("rpi-gpio in",GPIOInNode);
|
||||||
|
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
|
||||||
|
|
||||||
|
GPIOInNode.prototype.close = function() {
|
||||||
|
clearInterval(this._interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
GPIOOutNode.prototype.close = function() {
|
||||||
|
exec("gpio mode "+this.pin+" in");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@ -25,7 +25,7 @@ Object.size = function(obj) {
|
|||||||
|
|
||||||
function BlinkStick(n) {
|
function BlinkStick(n) {
|
||||||
RED.nodes.createNode(this,n);
|
RED.nodes.createNode(this,n);
|
||||||
var p1 = /^\#[A-Za-z0-9]{6}$/
|
var p1 = /^\#[A-Fa-f0-9]{6}$/
|
||||||
var p2 = /[0-9]+,[0-9]+,[0-9]+/
|
var p2 = /[0-9]+,[0-9]+,[0-9]+/
|
||||||
this.led = blinkstick.findFirst(); // maybe try findAll() (one day)
|
this.led = blinkstick.findFirst(); // maybe try findAll() (one day)
|
||||||
var node = this;
|
var node = this;
|
||||||
@ -33,21 +33,23 @@ function BlinkStick(n) {
|
|||||||
this.on("input", function(msg) {
|
this.on("input", function(msg) {
|
||||||
if (msg != null) {
|
if (msg != null) {
|
||||||
if (Object.size(node.led) !== 0) {
|
if (Object.size(node.led) !== 0) {
|
||||||
|
try {
|
||||||
if (p2.test(msg.payload)) {
|
if (p2.test(msg.payload)) {
|
||||||
var rgb = msg.payload.split(",");
|
var rgb = msg.payload.split(",");
|
||||||
node.led.setColor(parseInt(rgb[0])&255, parseInt(rgb[1])&255, parseInt(rgb[2])&255);
|
node.led.setColor(parseInt(rgb[0])&255, parseInt(rgb[1])&255, parseInt(rgb[2])&255);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
|
||||||
node.led.setColor(msg.payload);
|
node.led.setColor(msg.payload);
|
||||||
}
|
}
|
||||||
catch (err) {
|
|
||||||
node.warn("Incorrect format: "+msg.payload);
|
|
||||||
}
|
}
|
||||||
|
catch (err) {
|
||||||
|
node.warn("BlinkStick missing ?");
|
||||||
|
node.led = blinkstick.findFirst();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.warn("No BlinkStick found");
|
node.warn("No BlinkStick found");
|
||||||
|
node.led = blinkstick.findFirst();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -23,7 +23,7 @@ function Blink1Node(n) {
|
|||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var p1 = /^\#[A-Za-z0-9]{6}$/
|
var p1 = /^\#[A-Fa-f0-9]{6}$/
|
||||||
var p2 = /[0-9]+,[0-9]+,[0-9]+/
|
var p2 = /[0-9]+,[0-9]+,[0-9]+/
|
||||||
this.on("input", function(msg) {
|
this.on("input", function(msg) {
|
||||||
if (blink1) {
|
if (blink1) {
|
||||||
@ -53,7 +53,7 @@ function Blink1Node(n) {
|
|||||||
var blink1 = new Blink1.Blink1();
|
var blink1 = new Blink1.Blink1();
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
node.error("no Blink1 found");
|
node.error("No Blink1 found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
nodes/hardware/78-ledborg.html
Normal file
50
nodes/hardware/78-ledborg.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!--
|
||||||
|
Copyright 2013 IBM Corp.
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="ledborg">
|
||||||
|
<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>
|
||||||
|
<div class="form-tips">Expects a msg.payload with PiBorg three digit rgb colour string. 000 -> 222</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-help-name="ledborg">
|
||||||
|
<p>PiBorg LedBorg LED output node. Expects a <b>msg.payload</b> with a three digit rgb triple, from <b>000</b> to <b>222</b>.</p>
|
||||||
|
<p>See <i><a href="http://www.piborg.com/ledborg/install" target="_new">the PiBorg site</a></i> for more information.</p>
|
||||||
|
<p>You can also now use a <b>msg.payload</b> in the standard hex format "#rrggbb". The clip levels are :</p>
|
||||||
|
<p><pre>0x00 - 0x57 = off<br/>0x58 - 0xA7 = 50%<br/>0xA8 - 0xFF = fully on</pre></p>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('ledborg',{
|
||||||
|
category: 'output',
|
||||||
|
color:"GoldenRod",
|
||||||
|
defaults: {
|
||||||
|
name: {value:""}
|
||||||
|
},
|
||||||
|
inputs:1,
|
||||||
|
outputs:0,
|
||||||
|
icon: "light.png",
|
||||||
|
align: "right",
|
||||||
|
label: function() {
|
||||||
|
return this.name||"ledborg";
|
||||||
|
},
|
||||||
|
labelStyle: function() {
|
||||||
|
return this.name?"node_label_italic":"";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
53
nodes/hardware/78-ledborg.js
Normal file
53
nodes/hardware/78-ledborg.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2013 IBM Corp.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var RED = require("../../red/red");
|
||||||
|
var util = require('util');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
// check if /dev/ledborg exists - if not then don't even show the node.
|
||||||
|
if (!fs.existsSync("/dev/ledborg")) {
|
||||||
|
util.log("[78-ledborg.js] Error: PiBorg hardware : LedBorg not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function LedBorgNode(n) {
|
||||||
|
RED.nodes.createNode(this,n);
|
||||||
|
var p1 = /[0-2][0-2][0-2]/
|
||||||
|
var p2 = /^\#[A-Fa-f0-9]{6}$/
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
this.on("input", function(msg) {
|
||||||
|
if (p1.test(msg.payload)) {
|
||||||
|
fs.writeFile('/dev/ledborg', msg.payload, function (err) {
|
||||||
|
if (err) node.warn(msg.payload+" : No LedBorg found");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (p2.test(msg.payload)) {
|
||||||
|
var r = Math.floor(parseInt(msg.payload.slice(1,3),16)/88).toString();
|
||||||
|
var g = Math.floor(parseInt(msg.payload.slice(3,5),16)/88).toString();
|
||||||
|
var b = Math.floor(parseInt(msg.payload.slice(5),16)/88).toString();
|
||||||
|
fs.writeFile('/dev/ledborg', r+g+b, function (err) {
|
||||||
|
if (err) node.warn(r+g+b+" : No LedBorg found");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node.warn("Invalid LedBorg colour code");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RED.nodes.registerType("ledborg",LedBorgNode);
|
@ -37,15 +37,17 @@ function HTTPIn(n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RED.nodes.registerType("http in",HTTPIn);
|
||||||
|
|
||||||
HTTPIn.prototype.close = function() {
|
HTTPIn.prototype.close = function() {
|
||||||
var routes = redUI.app.routes[this.method];
|
console.log(RED.app.routes[this.method]);
|
||||||
|
var routes = RED.app.routes[this.method];
|
||||||
for (var i in routes) {
|
for (var i in routes) {
|
||||||
if (routes[i].path == this.url) {
|
if (routes[i].path == this.url) {
|
||||||
routes.splice(i,1);
|
routes.splice(i,1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(RED.app.routes[this.method]);
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.nodes.registerType("http in",HTTPIn);
|
|
||||||
|
@ -16,22 +16,36 @@
|
|||||||
|
|
||||||
<script type="text/x-red" data-template-name="tcp in">
|
<script type="text/x-red" data-template-name="tcp in">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-host"><i class="icon-bookmark"></i> Host</label>
|
<label for="node-input-server"><i class="icon-resize-small"></i> Type</label>
|
||||||
<input type="text" id="node-input-host" placeholder="localhost" style="width: 40%;" >
|
<select id="node-input-server" style="width:120px; margin-right:5px;">
|
||||||
|
<option value="server">Listen on</option>
|
||||||
|
<option value="client">Connect to</option>
|
||||||
|
</select>
|
||||||
|
port <input type="text" id="node-input-port" style="width: 50px">
|
||||||
|
</div>
|
||||||
|
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
|
||||||
|
at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 40%;">
|
||||||
|
</div>
|
||||||
|
|
||||||
<label for="node-input-port" style="margin-left: 10px; width: 35px;"> Port</label>
|
|
||||||
<input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label> </label>
|
<label><i class="icon-th"></i> Output</label>
|
||||||
<input type="checkbox" id="node-input-server" placeholder="server" style="display: inline-block; width: auto; vertical-align: top;">
|
a
|
||||||
<label for="node-input-server" style="width: 70%;">Be a server socket ?</label>
|
<select id="node-input-datamode" style="width:110px;">
|
||||||
|
<option value="stream">stream of</option>
|
||||||
|
<option value="single">single</option>
|
||||||
|
</select>
|
||||||
|
<select id="node-input-datatype" style="width:140px;">
|
||||||
|
<option value="buffer">Buffer</option>
|
||||||
|
<option value="utf8">String</option>
|
||||||
|
<option value="base64">Base64 String</option>
|
||||||
|
</select>
|
||||||
|
payload<span id="node-input-datamode-plural">s</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
|
||||||
<label> </label>
|
<div id="node-row-newline" class="form-row hidden" style="padding-left: 110px;">
|
||||||
<input type="checkbox" id="node-input-base64" placeholder="base64" style="display: inline-block; width: auto; vertical-align: top;">
|
delimited by <input type="text" id="node-input-newline" style="width: 110px;">
|
||||||
<label for="node-input-base64" style="width: 70%;">Base64 encode payload ?</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
|
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
|
||||||
<input type="text" id="node-input-topic" placeholder="Topic">
|
<input type="text" id="node-input-topic" placeholder="Topic">
|
||||||
@ -40,15 +54,11 @@
|
|||||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips">Tip: sends the received data as a Buffer object (not a String).<br/>If you select server socket the host defaults to localhost.</div>
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="tcp in">
|
<script type="text/x-red" data-help-name="tcp in">
|
||||||
<p>Provides a choice of tcp input connections. Can either be a client - or provide a listening socket.</p>
|
<p>Provides a choice of tcp inputs. Can either connect to a remote tcp port,
|
||||||
<p>The TCP node produces a <i>BUFFER</i> object <b></b>msg.payload</b> and NOT a String. If you need a String then use <i>.toString()</i> on <b>msg.payload</b> in your next function block.</p>
|
or accept incoming connections.</p>
|
||||||
<p>It also provides <b>msg.fromip</b> of the form ipaddress:port .</p>
|
|
||||||
<p>You can select Base64 encoding if you want to make it easy to preserve the complete message as a string.</p>
|
|
||||||
<p>In case of disconnection the client trys to reconnect every 10 secs. Topic is optional.</p>
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -56,24 +66,51 @@
|
|||||||
category: 'input',
|
category: 'input',
|
||||||
color:"Silver",
|
color:"Silver",
|
||||||
defaults: {
|
defaults: {
|
||||||
host: {value:"127.0.0.1",required:true},
|
server: {value:"server",required:true},
|
||||||
|
host: {value:"",validate:function(v) { return (this.server == "server")||v.length > 0;} },
|
||||||
port: {value:"",required:true,validate:RED.validators.number()},
|
port: {value:"",required:true,validate:RED.validators.number()},
|
||||||
base64: {value:false,required:true},
|
datamode:{value:"stream"},
|
||||||
server: {value:false,required:true},
|
datatype:{value:"buffer"},
|
||||||
|
newline:{value:""},
|
||||||
topic: {value:""},
|
topic: {value:""},
|
||||||
name: {value:""}
|
name: {value:""},
|
||||||
|
base64: {/*deprecated*/ value:false,required:true}
|
||||||
},
|
},
|
||||||
inputs:0,
|
inputs:0,
|
||||||
outputs:1,
|
outputs:1,
|
||||||
icon: "bridge-dash.png",
|
icon: "bridge-dash.png",
|
||||||
label: function() {
|
label: function() {
|
||||||
if ((this.host!="") & (this.port!="")) {
|
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||||
return this.name||(this.host+":"+this.port);
|
|
||||||
}
|
|
||||||
else { return "tcp in"; }
|
|
||||||
},
|
},
|
||||||
labelStyle: function() {
|
labelStyle: function() {
|
||||||
return this.name?"node_label_italic":"";
|
return this.name?"node_label_italic":"";
|
||||||
|
},
|
||||||
|
oneditprepare: function() {
|
||||||
|
var updateOptions = function() {
|
||||||
|
var sockettype = $("#node-input-server option:selected").val();
|
||||||
|
if (sockettype == "client") {
|
||||||
|
$("#node-input-host-row").show();
|
||||||
|
} else {
|
||||||
|
$("#node-input-host-row").hide();
|
||||||
|
}
|
||||||
|
var datamode = $("#node-input-datamode option:selected").val();
|
||||||
|
var datatype = $("#node-input-datatype option:selected").val();
|
||||||
|
if (datamode == "stream") {
|
||||||
|
$("#node-input-datamode-plural").show();
|
||||||
|
if (datatype == "utf8") {
|
||||||
|
$("#node-row-newline").show();
|
||||||
|
} else {
|
||||||
|
$("#node-row-newline").hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$("#node-input-datamode-plural").hide();
|
||||||
|
$("#node-row-newline").hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updateOptions();
|
||||||
|
$("#node-input-server").change(updateOptions);
|
||||||
|
$("#node-input-datatype").change(updateOptions);
|
||||||
|
$("#node-input-datamode").change(updateOptions);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
var RED = require("../../red/red");
|
var RED = require("../../red/red");
|
||||||
var reConnect = RED.settings.socketReconnectTime||10000;
|
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
|
|
||||||
function TcpIn(n) {
|
function TcpIn(n) {
|
||||||
@ -23,73 +23,123 @@ function TcpIn(n) {
|
|||||||
this.host = n.host;
|
this.host = n.host;
|
||||||
this.port = n.port * 1;
|
this.port = n.port * 1;
|
||||||
this.topic = n.topic;
|
this.topic = n.topic;
|
||||||
|
this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
|
||||||
|
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
|
||||||
|
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
|
||||||
this.base64 = n.base64;
|
this.base64 = n.base64;
|
||||||
this.server = n.server;
|
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
||||||
|
this.closing = false;
|
||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
if (!node.server) {
|
if (!node.server) {
|
||||||
|
var buffer = null;
|
||||||
var client;
|
var client;
|
||||||
var to;
|
var reconnectTimeout;
|
||||||
|
|
||||||
function setupTcpClient() {
|
function setupTcpClient() {
|
||||||
node.log('connecting to port '+node.port);
|
node.log("connecting to "+node.host+":"+node.port);
|
||||||
client = net.connect(node.port, node.host, function() {
|
client = net.connect(node.port, node.host, function() {
|
||||||
node.log("input connected to "+node.host+":"+node.port);
|
buffer = (node.datatype == 'buffer')? new Buffer(0):"";
|
||||||
|
node.log("connected to "+node.host+":"+node.port);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('data', function (data) {
|
client.on('data', function (data) {
|
||||||
var msg;
|
if (node.datatype != 'buffer') {
|
||||||
if (node.base64) { msg = { topic:node.topic, payload:new Buffer(data).toString('base64') }; }
|
data = data.toString(node.datatype);
|
||||||
else { msg = {topic:node.topic, payload:data}; }
|
}
|
||||||
|
if (node.stream) {
|
||||||
|
if ((typeof data) === "string" && node.newline != "") {
|
||||||
|
buffer = buffer+data;
|
||||||
|
var parts = buffer.split(node.newline);
|
||||||
|
for (var i = 0;i<parts.length-1;i+=1) {
|
||||||
|
var msg = {topic:node.topic, payload:parts[i]};
|
||||||
node.send(msg);
|
node.send(msg);
|
||||||
|
}
|
||||||
|
buffer = parts[parts.length-1];
|
||||||
|
} else {
|
||||||
|
var msg = {topic:node.topic, payload:data};
|
||||||
|
node.send(msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((typeof data) === "string") {
|
||||||
|
buffer = buffer+data;
|
||||||
|
} else {
|
||||||
|
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('end', function() {
|
client.on('end', function() {
|
||||||
node.log("ended");
|
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
|
||||||
|
var msg = {topic:node.topic,payload:buffer};
|
||||||
|
node.send(msg);
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('close', function() {
|
client.on('close', function() {
|
||||||
client.destroy();
|
node.log("connection lost to "+node.host+":"+node.port);
|
||||||
node.log('closed');
|
if (!node.closing) {
|
||||||
to = setTimeout(setupTcpClient, reConnect);
|
reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', function(err) {
|
client.on('error', function(err) {
|
||||||
node.log('error : '+err);
|
node.log(err);
|
||||||
//to = setTimeout(setupTcpClient, reConnect);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setupTcpClient();
|
setupTcpClient();
|
||||||
|
|
||||||
this._close = function() {
|
this._close = function() {
|
||||||
|
this.closing = true;
|
||||||
client.end();
|
client.end();
|
||||||
clearTimeout(to);
|
clearTimeout(reconnectTimeout);
|
||||||
node.log('input stopped');
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var server = net.createServer(function (socket) {
|
var server = net.createServer(function (socket) {
|
||||||
var buffer = null;
|
var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
|
||||||
socket.on('data', function (chunk) {
|
socket.on('data', function (data) {
|
||||||
//if (buffer == null) {
|
if (node.datatype != 'buffer') {
|
||||||
// buffer = chunk;
|
data = data.toString(node.datatype);
|
||||||
//} else {
|
}
|
||||||
//buffer = Buffer.concat([buffer,chunk]);
|
|
||||||
var msg = {topic:node.topic, payload:chunk, fromip:socket.remoteAddress+':'+socket.remotePort};
|
if (node.stream) {
|
||||||
|
if ((typeof data) === "string" && node.newline != "") {
|
||||||
|
buffer = buffer+data;
|
||||||
|
var parts = buffer.split(node.newline);
|
||||||
|
for (var i = 0;i<parts.length-1;i+=1) {
|
||||||
|
var msg = {topic:node.topic, payload:parts[i]};
|
||||||
node.send(msg);
|
node.send(msg);
|
||||||
//}
|
}
|
||||||
|
buffer = parts[parts.length-1];
|
||||||
|
} else {
|
||||||
|
var msg = {topic:node.topic, payload:data};
|
||||||
|
node.send(msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((typeof data) === "string") {
|
||||||
|
buffer = buffer+data;
|
||||||
|
} else {
|
||||||
|
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
socket.on('end', function() {
|
socket.on('end', function() {
|
||||||
var msg = {topic:node.topic, payload:buffer, fromip:socket.remoteAddress+':'+socket.remotePort};
|
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
|
||||||
|
var msg = {topic:node.topic,payload:buffer};
|
||||||
node.send(msg);
|
node.send(msg);
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
socket.on('error',function(err) {
|
||||||
|
node.log(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
server.listen(node.port);
|
server.listen(node.port);
|
||||||
node.log('socket input on port '+node.port);
|
node.log('listening on port '+node.port);
|
||||||
|
|
||||||
this._close = function() {
|
this._close = function() {
|
||||||
|
this.closing = true;
|
||||||
server.close();
|
server.close();
|
||||||
node.log('socket input stopped');
|
node.log('stopped listening on port '+node.port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,34 +16,37 @@
|
|||||||
|
|
||||||
<script type="text/x-red" data-template-name="tcp out">
|
<script type="text/x-red" data-template-name="tcp out">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-host"><i class="icon-bookmark"></i> Host</label>
|
<label for="node-input-beserver"><i class="icon-resize-small"></i> Type</label>
|
||||||
<input type="text" id="node-input-host" placeholder="localhost" style="width: 40%;" >
|
<select id="node-input-beserver" style="width:120px; margin-right:5px;">
|
||||||
|
<option value="server">Listen on</option>
|
||||||
|
<option value="client">Connect to</option>
|
||||||
|
</select>
|
||||||
|
port <input type="text" id="node-input-port" style="width: 50px">
|
||||||
|
</div>
|
||||||
|
|
||||||
<label for="node-input-port" style="margin-left: 10px; width: 35px;"> Port</label>
|
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
|
||||||
<input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 40%;">
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label> </label>
|
|
||||||
<input type="checkbox" id="node-input-beserver" placeholder="server" style="display: inline-block; width: auto; vertical-align: top;">
|
|
||||||
<label for="node-input-beserver" style="width: 70%;">Be a server socket ?</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label> </label>
|
<label> </label>
|
||||||
<input type="checkbox" id="node-input-base64" placeholder="base64" style="display: inline-block; width: auto; vertical-align: top;">
|
<input type="checkbox" id="node-input-base64" placeholder="base64" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
<label for="node-input-base64" style="width: 70%;">Decode Base64 message ?</label>
|
<label for="node-input-base64" style="width: 70%;">Decode Base64 message ?</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips">Tip: If you select server socket the host defaults to localhost.</div>
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="tcp out">
|
<script type="text/x-red" data-help-name="tcp out">
|
||||||
<p>Provides a choice of tcp output connections. Can either connect out - or provide a socket connection.</p>
|
<p>Provides a choice of tcp outputs. Can either connect to a remote tcp port,
|
||||||
|
or accept incoming connections.</p>
|
||||||
<p>Only <b>msg.payload</b> is sent.</p>
|
<p>Only <b>msg.payload</b> is sent.</p>
|
||||||
<p>You can select Base64 decoding if you want to decode a message encoded by the input socket.</p>
|
<p>If <b>msg.payload</b> is a string containing a base64 encoding of binary
|
||||||
|
data, the Base64 decoding option will cause it to be converted back to binary
|
||||||
|
before being sent.</p>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -51,9 +54,9 @@
|
|||||||
category: 'output',
|
category: 'output',
|
||||||
color:"Silver",
|
color:"Silver",
|
||||||
defaults: {
|
defaults: {
|
||||||
host: {value:"127.0.0.1",required:true},
|
host: {value:"",validate:function(v) { return (this.beserver == "server")||v.length > 0;} },
|
||||||
port: {value:"",required:true},
|
port: {value:"",required:true},
|
||||||
beserver: {value:false,required:true},
|
beserver: {value:"client",required:true},
|
||||||
base64: {value:false,required:true},
|
base64: {value:false,required:true},
|
||||||
name: {value:""}
|
name: {value:""}
|
||||||
},
|
},
|
||||||
@ -62,12 +65,22 @@
|
|||||||
icon: "bridge-dash.png",
|
icon: "bridge-dash.png",
|
||||||
align: "right",
|
align: "right",
|
||||||
label: function() {
|
label: function() {
|
||||||
var lab = this.host+":"+this.port;
|
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||||
if (this.server) lab = "tcp out:"+this.port;
|
|
||||||
return this.name||lab;
|
|
||||||
},
|
},
|
||||||
labelStyle: function() {
|
labelStyle: function() {
|
||||||
return (this.name)?"node_label_italic":"";
|
return (this.name)?"node_label_italic":"";
|
||||||
|
},
|
||||||
|
oneditprepare: function() {
|
||||||
|
var updateOptions = function() {
|
||||||
|
var sockettype = $("#node-input-beserver option:selected").val();
|
||||||
|
if (sockettype == "client") {
|
||||||
|
$("#node-input-host-row").show();
|
||||||
|
} else {
|
||||||
|
$("#node-input-host-row").hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updateOptions();
|
||||||
|
$("#node-input-beserver").change(updateOptions);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
var RED = require("../../red/red");
|
var RED = require("../../red/red");
|
||||||
var reConnect = RED.settings.socketReconnectTime||10000;
|
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
|
|
||||||
function TcpOut(n) {
|
function TcpOut(n) {
|
||||||
@ -25,67 +25,93 @@ function TcpOut(n) {
|
|||||||
this.base64 = n.base64;
|
this.base64 = n.base64;
|
||||||
this.beserver = n.beserver;
|
this.beserver = n.beserver;
|
||||||
this.name = n.name;
|
this.name = n.name;
|
||||||
|
this.closing = false;
|
||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
if (!node.beserver) {
|
if (!node.beserver||node.beserver=="client") {
|
||||||
var client = new net.Socket();
|
var reconnectTimeout;
|
||||||
var to;
|
var client = null;
|
||||||
|
var connected = false;
|
||||||
|
|
||||||
function setupTcpClient() {
|
function setupTcpClient() {
|
||||||
client.connect(node.port, node.host, function() {
|
node.log("connecting to "+node.host+":"+node.port);
|
||||||
node.log("output connected to "+node.host+":"+node.port);
|
client = net.connect(node.port, node.host, function() {
|
||||||
|
connected = true;
|
||||||
|
node.log("connected to "+node.host+":"+node.port);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', function (err) {
|
client.on('error', function (err) {
|
||||||
node.error('error : '+err);
|
node.log('error : '+err);
|
||||||
to = setTimeout(setupTcpClient, reConnect);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('end', function (err) {
|
client.on('end', function (err) {
|
||||||
node.log("output disconnected");
|
|
||||||
to = setTimeout(setupTcpClient, reConnect);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('close', function() {
|
client.on('close', function() {
|
||||||
|
node.log("connection lost to "+node.host+":"+node.port);
|
||||||
|
connected = false;
|
||||||
client.destroy();
|
client.destroy();
|
||||||
node.log('closed');
|
if (!node.closing) {
|
||||||
to = setTimeout(setupTcpClient, reConnect);
|
reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
|
||||||
});
|
|
||||||
|
|
||||||
node.on("input", function(msg) {
|
|
||||||
if (msg.payload != null) {
|
|
||||||
if (node.base64) { client.write(new Buffer(msg.payload,'base64')); }
|
|
||||||
else { client.write(msg.payload);}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setupTcpClient();
|
setupTcpClient();
|
||||||
|
|
||||||
|
|
||||||
|
node.on("input", function(msg) {
|
||||||
|
if (connected && msg.payload != null) {
|
||||||
|
if (Buffer.isBuffer(msg.payload)) {
|
||||||
|
client.write(msg.payload);
|
||||||
|
} else if (typeof msg.payload === "string" && node.base64) {
|
||||||
|
client.write(new Buffer(msg.payload,'base64'));
|
||||||
|
} else {
|
||||||
|
client.write(new Buffer(""+msg.payload));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
this._close = function() {
|
this._close = function() {
|
||||||
|
this.closing = true;
|
||||||
client.end();
|
client.end();
|
||||||
clearTimeout(to);
|
clearTimeout(reconnectTimeout);
|
||||||
node.log('output stopped');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
var connectedSockets = [];
|
||||||
var server = net.createServer(function (socket) {
|
var server = net.createServer(function (socket) {
|
||||||
socket.on("connect",function() {
|
var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
|
||||||
node.log("Connection from "+socket.remoteAddress);
|
node.log("connection from "+remoteDetails);
|
||||||
|
connectedSockets.push(socket);
|
||||||
|
socket.on('close',function() {
|
||||||
|
node.log("connection closed from "+remoteDetails);
|
||||||
|
connectedSockets.splice(connectedSockets.indexOf(socket),1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
node.on("input", function(msg) {
|
node.on("input", function(msg) {
|
||||||
if (msg.payload != null) {
|
if (msg.payload != null) {
|
||||||
if (node.base64) { socket.write(new Buffer(msg.payload,'base64')); }
|
var buffer;
|
||||||
else { socket.write(msg.payload);}
|
if (Buffer.isBuffer(msg.payload)) {
|
||||||
|
buffer = msg.payload;
|
||||||
|
} else if (typeof msg.payload === "string" && node.base64) {
|
||||||
|
buffer = new Buffer(msg.payload,'base64');
|
||||||
|
} else {
|
||||||
|
buffer = new Buffer(""+msg.payload);
|
||||||
|
}
|
||||||
|
for (var i = 0; i<connectedSockets.length;i+=1) {
|
||||||
|
connectedSockets[i].write(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
server.listen(node.port);
|
server.listen(node.port);
|
||||||
node.log('socket output on port '+node.port);
|
node.log('listening on port '+node.port);
|
||||||
|
|
||||||
this._close = function() {
|
this._close = function() {
|
||||||
server.close();
|
server.close();
|
||||||
node.log('output stopped');
|
node.log('stopped listening on port '+node.port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
nodes/storage/67-leveldb.html
Normal file
114
nodes/storage/67-leveldb.html
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<!--
|
||||||
|
Copyright 2013 IBM Corp.
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="leveldbase">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-db"><i class="icon-briefcase"></i> Database</label>
|
||||||
|
<input type="text" id="node-config-input-db" placeholder="database path/name">
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('leveldbase',{
|
||||||
|
category: 'config',
|
||||||
|
defaults: {
|
||||||
|
db: {value:"",required:true}
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.db;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="leveldb in">
|
||||||
|
<div class="form-row node-input-level">
|
||||||
|
<label for="node-input-level"><i class="icon-briefcase"></i> Database</label>
|
||||||
|
<input type="text" id="node-input-level">
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-help-name="leveldb in">
|
||||||
|
<p>Uses <a href="https://code.google.com/p/leveldb/" target="_new"><i>LevelDB</i></a> for a simple key value pair database.</p>
|
||||||
|
<p>Use this node to <b>get</b>, or retrieve the data already saved in the database.</p>
|
||||||
|
<p><b>msg.topic</b> must hold the <i>key</i> for the database, and the result is returned in <b>msg.payload</b>.</p>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('leveldb in',{
|
||||||
|
category: 'storage-input',
|
||||||
|
color:"#dbb84d",
|
||||||
|
defaults: {
|
||||||
|
level: {type:"leveldbase",required:true},
|
||||||
|
name: {value:""}
|
||||||
|
},
|
||||||
|
inputs:1,
|
||||||
|
outputs:1,
|
||||||
|
icon: "leveldb.png",
|
||||||
|
label: function() {
|
||||||
|
var levelNode = RED.nodes.node(this.level);
|
||||||
|
return this.name||(levelNode?levelNode.label():"leveldb");
|
||||||
|
},
|
||||||
|
labelStyle: function() {
|
||||||
|
return this.name?"node_label_italic":"";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="leveldb out">
|
||||||
|
<div class="form-row node-input-level">
|
||||||
|
<label for="node-input-level"><i class="icon-briefcase"></i> Database</label>
|
||||||
|
<input type="text" id="node-input-level">
|
||||||
|
</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>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/x-red" data-help-name="leveldb out">
|
||||||
|
<p>Uses <a href="https://code.google.com/p/leveldb/" target="_new"><i>LevelDB</i></a> for a simple key value pair database.</p>
|
||||||
|
<p>Use this node to <b>put</b> (save) the <b>msg.payload</b> to the named database file, using <b>msg.topic</b> as the key.</p>
|
||||||
|
<p>To <b>delete</b> information do a <b>put</b> to the required <b>msg.topic</b> (key) with a <b>msg.payload</b> of <b><i>null</i></b>.</p>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('leveldb out',{
|
||||||
|
category: 'storage-output',
|
||||||
|
color:"#dbb84d",
|
||||||
|
defaults: {
|
||||||
|
level: {type:"leveldbase",required:true},
|
||||||
|
op: {value:"put",required:true},
|
||||||
|
name: {value:""}
|
||||||
|
},
|
||||||
|
inputs:1,
|
||||||
|
outputs:0,
|
||||||
|
icon: "leveldb.png",
|
||||||
|
align: "right",
|
||||||
|
label: function() {
|
||||||
|
var levelNode = RED.nodes.node(this.level);
|
||||||
|
return this.name||(levelNode?levelNode.label():"leveldb");
|
||||||
|
},
|
||||||
|
labelStyle: function() {
|
||||||
|
return this.name?"node_label_italic":"";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
90
nodes/storage/67-leveldb.js
Normal file
90
nodes/storage/67-leveldb.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2013 IBM Corp.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var RED = require("../../red/red");
|
||||||
|
var lvldb = require('leveldb');
|
||||||
|
|
||||||
|
function LevelNode(n) {
|
||||||
|
RED.nodes.createNode(this,n);
|
||||||
|
this.dbname = n.db;
|
||||||
|
lvldb.open(this.dbname, { create_if_missing: true }, onOpen);
|
||||||
|
var node = this;
|
||||||
|
function onOpen(err, db) {
|
||||||
|
if (err) node.error(err);
|
||||||
|
node.db = db;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("leveldbase",LevelNode);
|
||||||
|
|
||||||
|
|
||||||
|
function LevelDBNodeIn(n) {
|
||||||
|
RED.nodes.createNode(this,n);
|
||||||
|
this.level = n.level;
|
||||||
|
this.op = n.op;
|
||||||
|
this.levelConfig = RED.nodes.getNode(this.level);
|
||||||
|
|
||||||
|
if (this.levelConfig) {
|
||||||
|
var node = this;
|
||||||
|
node.on("input", function(msg) {
|
||||||
|
if (typeof msg.topic === 'string') {
|
||||||
|
node.levelConfig.db.get(msg.topic, function(err, value) {
|
||||||
|
if (err) node.error(err);
|
||||||
|
msg.payload = JSON.parse(value);
|
||||||
|
delete msg.cmd;
|
||||||
|
node.send(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (typeof msg.topic !== 'string') node.error("msg.topic (the key is not defined");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.error("LevelDB database name not configured");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("leveldb in",LevelDBNodeIn);
|
||||||
|
|
||||||
|
|
||||||
|
function LevelDBNodeOut(n) {
|
||||||
|
RED.nodes.createNode(this,n);
|
||||||
|
this.level = n.level;
|
||||||
|
this.levelConfig = RED.nodes.getNode(this.level);
|
||||||
|
|
||||||
|
if (this.levelConfig) {
|
||||||
|
var node = this;
|
||||||
|
node.on("input", function(msg) {
|
||||||
|
if (typeof msg.topic === 'string') {
|
||||||
|
console.log(msg);
|
||||||
|
if (msg.payload === null) {
|
||||||
|
node.levelConfig.db.del(msg.topic);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node.levelConfig.db.put(msg.topic, JSON.stringify(msg.payload), function(err) {
|
||||||
|
if (err) node.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (typeof msg.topic !== 'string') node.error("msg.topic (the key is not defined");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.error("LevelDB database name not configured");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("leveldb out",LevelDBNodeOut);
|
BIN
public/icons/leveldb.png
Normal file
BIN
public/icons/leveldb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
@ -96,7 +96,7 @@ RED.editor = function() {
|
|||||||
valid = value !== "";
|
valid = value !== "";
|
||||||
}
|
}
|
||||||
if (valid && "validate" in node._def.defaults[property]) {
|
if (valid && "validate" in node._def.defaults[property]) {
|
||||||
valid = node._def.defaults[property].validate(value);
|
valid = node._def.defaults[property].validate.call(node,value);
|
||||||
}
|
}
|
||||||
if (valid && node._def.defaults[property].type && RED.nodes.getType(node._def.defaults[property].type)) {
|
if (valid && node._def.defaults[property].type && RED.nodes.getType(node._def.defaults[property].type)) {
|
||||||
valid = (value != "_ADD_");
|
valid = (value != "_ADD_");
|
||||||
|
@ -16,14 +16,22 @@
|
|||||||
RED.notify = function() {
|
RED.notify = function() {
|
||||||
var currentNotifications = [];
|
var currentNotifications = [];
|
||||||
var c = 0;
|
var c = 0;
|
||||||
return function(msg,type) {
|
return function(msg,type,fixed) {
|
||||||
while (currentNotifications.length > 4) {
|
if (currentNotifications.length > 4) {
|
||||||
var n = currentNotifications[0];
|
var ll = currentNotifications.length;
|
||||||
window.clearTimeout(n.id);
|
for (var i = 0;ll > 4 && i<currentNotifications.length;i+=1) {
|
||||||
n.slideup();
|
var n = currentNotifications[i];
|
||||||
|
if (!n.fixed) {
|
||||||
|
window.clearTimeout(n.timeoutid);
|
||||||
|
n.close();
|
||||||
|
ll -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var n = document.createElement("div");
|
var n = document.createElement("div");
|
||||||
|
n.id="red-notification-"+c;
|
||||||
n.className = "alert";
|
n.className = "alert";
|
||||||
|
n.fixed = fixed;
|
||||||
if (type) {
|
if (type) {
|
||||||
n.className = "alert alert-"+type;
|
n.className = "alert alert-"+type;
|
||||||
}
|
}
|
||||||
@ -31,18 +39,21 @@ RED.notify = function() {
|
|||||||
n.innerHTML = msg;
|
n.innerHTML = msg;
|
||||||
$("#notifications").append(n);
|
$("#notifications").append(n);
|
||||||
$(n).slideDown(300);
|
$(n).slideDown(300);
|
||||||
var slideup = function() {
|
n.close = function() {
|
||||||
var nn = n;
|
var nn = n;
|
||||||
return function() {
|
return function() {
|
||||||
currentNotifications.shift();
|
currentNotifications.splice(currentNotifications.indexOf(nn),1);
|
||||||
$(nn).slideUp(300, function() {
|
$(nn).slideUp(300, function() {
|
||||||
nn.parentNode.removeChild(nn);
|
nn.parentNode.removeChild(nn);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
var id = window.setTimeout(slideup,3000);
|
if (!fixed) {
|
||||||
currentNotifications.push({id:id,slideup:slideup,c:c});
|
n.timeoutid = window.setTimeout(n.close,3000);
|
||||||
|
}
|
||||||
|
currentNotifications.push(n);
|
||||||
c+=1;
|
c+=1;
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ RED.sidebar = function() {
|
|||||||
$("#main-container").removeClass("sidebar-closed");
|
$("#main-container").removeClass("sidebar-closed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
toggleSidebar();
|
||||||
|
|
||||||
function addTab(title,content) {
|
function addTab(title,content) {
|
||||||
var tab = document.createElement("li");
|
var tab = document.createElement("li");
|
||||||
|
@ -238,6 +238,9 @@ a.brand img {
|
|||||||
.node_label_italic {
|
.node_label_italic {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
.node_label_white {
|
||||||
|
fill: #eee !important;
|
||||||
|
}
|
||||||
.node_label {
|
.node_label {
|
||||||
stroke-width: 0;
|
stroke-width: 0;
|
||||||
fill: #333;
|
fill: #333;
|
||||||
|
62
red/nodes.js
62
red/nodes.js
@ -98,6 +98,7 @@ var node_type_registry = (function() {
|
|||||||
if (! node_configs[configFilename]) {
|
if (! node_configs[configFilename]) {
|
||||||
node_configs[configFilename] = fs.readFileSync(configFilename,'utf8');
|
node_configs[configFilename] = fs.readFileSync(configFilename,'utf8');
|
||||||
}
|
}
|
||||||
|
events.emit("type-registered",type);
|
||||||
} else {
|
} else {
|
||||||
util.log("["+type+"] missing template file: "+configFilename);
|
util.log("["+type+"] missing template file: "+configFilename);
|
||||||
}
|
}
|
||||||
@ -106,9 +107,6 @@ var node_type_registry = (function() {
|
|||||||
get: function(type) {
|
get: function(type) {
|
||||||
return node_types[type];
|
return node_types[type];
|
||||||
},
|
},
|
||||||
registerNodeConfig: function(type,config) {
|
|
||||||
node_configs[type] = config;
|
|
||||||
},
|
|
||||||
getNodeConfigs: function() {
|
getNodeConfigs: function() {
|
||||||
var result = "";
|
var result = "";
|
||||||
for (var nt in node_configs) {
|
for (var nt in node_configs) {
|
||||||
@ -256,33 +254,75 @@ module.exports.load = function() {
|
|||||||
|
|
||||||
loadNodes("nodes");
|
loadNodes("nodes");
|
||||||
|
|
||||||
events.emit("nodes-loaded");
|
//events.emit("nodes-loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var activeConfig = null;
|
||||||
|
var missingTypes = [];
|
||||||
|
|
||||||
|
events.on('type-registered',function(type) {
|
||||||
|
if (missingTypes.length > 0) {
|
||||||
|
var i = missingTypes.indexOf(type);
|
||||||
|
if (i != -1) {
|
||||||
|
missingTypes.splice(i,1);
|
||||||
|
util.log("[red] Missing type registered: "+type);
|
||||||
|
}
|
||||||
|
if (missingTypes.length == 0) {
|
||||||
|
parseConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports.getNode = function(nid) {
|
module.exports.getNode = function(nid) {
|
||||||
return registry.get(nid);
|
return registry.get(nid);
|
||||||
}
|
}
|
||||||
module.exports.parseConfig = function(conf) {
|
module.exports.setConfig = function(conf) {
|
||||||
|
if (activeConfig&&activeConfig.length > 0) {
|
||||||
|
util.log("[red] Stopping flows");
|
||||||
|
}
|
||||||
registry.clear();
|
registry.clear();
|
||||||
|
activeConfig = conf;
|
||||||
|
parseConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseConfig = function() {
|
||||||
|
|
||||||
|
missingTypes = [];
|
||||||
|
for (var i in activeConfig) {
|
||||||
|
var type = activeConfig[i].type;
|
||||||
|
var nt = node_type_registry.get(type);
|
||||||
|
if (!nt && missingTypes.indexOf(type) == -1) {
|
||||||
|
missingTypes.push(type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (missingTypes.length > 0) {
|
||||||
|
util.log("[red] Waiting for missing types to be registered:");
|
||||||
|
for (var i in missingTypes) {
|
||||||
|
util.log("[red] - "+missingTypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
util.log("[red] Starting flows");
|
||||||
events.emit("nodes-starting");
|
events.emit("nodes-starting");
|
||||||
for (var i in conf) {
|
for (var i in activeConfig) {
|
||||||
var nn = null;
|
var nn = null;
|
||||||
var nt = node_type_registry.get(conf[i].type);
|
var nt = node_type_registry.get(activeConfig[i].type);
|
||||||
if (nt) {
|
if (nt) {
|
||||||
try {
|
try {
|
||||||
nn = new nt(conf[i]);
|
nn = new nt(activeConfig[i]);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
util.log("[red] "+conf[i].type+" : "+err);
|
util.log("[red] "+activeConfig[i].type+" : "+err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log(nn);
|
// console.log(nn);
|
||||||
if (nn == null) {
|
if (nn == null) {
|
||||||
util.log("[red] unknown type: "+conf[i].type);
|
util.log("[red] unknown type: "+activeConfig[i].type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ function createServer(_server,settings) {
|
|||||||
if(err) {
|
if(err) {
|
||||||
util.log(err);
|
util.log(err);
|
||||||
} else {
|
} else {
|
||||||
redNodes.parseConfig(JSON.parse(fullBody));
|
redNodes.setConfig(JSON.parse(fullBody));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -79,13 +79,12 @@ function createServer(_server,settings) {
|
|||||||
util.log('or any other errors are resolved');
|
util.log('or any other errors are resolved');
|
||||||
util.log("------------------------------------------");
|
util.log("------------------------------------------");
|
||||||
|
|
||||||
util.log("[red] Loading workspace flow : "+rulesfile);
|
|
||||||
|
|
||||||
|
|
||||||
fs.exists(rulesfile, function (exists) {
|
fs.exists(rulesfile, function (exists) {
|
||||||
if (exists) {
|
if (exists) {
|
||||||
|
util.log("[red] Loading workspace flow : "+rulesfile);
|
||||||
fs.readFile(rulesfile,'utf8',function(err,data) {
|
fs.readFile(rulesfile,'utf8',function(err,data) {
|
||||||
redNodes.parseConfig(JSON.parse(data));
|
redNodes.setConfig(JSON.parse(data));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -17,6 +17,7 @@ module.exports = {
|
|||||||
uiPort: 1880,
|
uiPort: 1880,
|
||||||
mqttReconnectTime: 15000,
|
mqttReconnectTime: 15000,
|
||||||
serialReconnectTime: 15000,
|
serialReconnectTime: 15000,
|
||||||
|
debugMaxLength: 1000,
|
||||||
|
|
||||||
// You can protect the user interface with a userid and password by using the following property
|
// You can protect the user interface with a userid and password by using the following property
|
||||||
// the password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
|
// the password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
|
||||||
|
Loading…
Reference in New Issue
Block a user