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

Fix merge conflicts on i18n

This commit is contained in:
Nick O'Leary 2015-07-15 10:24:44 +01:00
commit 5dc0c0e968
35 changed files with 660 additions and 379 deletions

View File

@ -4,10 +4,15 @@ node-red-node-rbe
A <a href="http://nodered.org" target="_new">Node-RED</a> node that provides A <a href="http://nodered.org" target="_new">Node-RED</a> node that provides
provides report-by-exception (RBE) and deadband capability. provides report-by-exception (RBE) and deadband capability.
The node blocks unless the incoming value changes - RBE mode, or
changes by more than a certain amount (absolute value or percentage) - deadband
mode.
Install Install
------- -------
Run the following command in the root directory of your Node-RED install Run the following command in your Node-RED install directory, usually
`~/.node-red`
npm install node-red-node-rbe npm install node-red-node-rbe
@ -23,7 +28,7 @@ handle multiple topics at the same time.
###RBE mode ###RBE mode
Outputs the **msg** if the **msg.payload** is different to the previous one. The node doesn't send any output until the **msg.payload** is different to the previous one.
Works on numbers and strings. Useful for filtering out repeated messages of the Works on numbers and strings. Useful for filtering out repeated messages of the
same value. Saves bandwidth, etc... same value. Saves bandwidth, etc...

BIN
function/rbe/icons/rbe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

View File

@ -0,0 +1,18 @@
{
"rbe": {
"label": {
"func": "Mode",
"name": "Name"
},
"placeholder":{
"bandgap": "e.g. 10 or 5%"
},
"opts": {
"rbe": "block unless value changes",
"deadband": "block unless changes by more than"
},
"warn": {
"nonumber": "no number found in payload"
}
}
}

View File

@ -1,6 +1,6 @@
{ {
"name" : "node-red-node-rbe", "name" : "node-red-node-rbe",
"version" : "0.0.7", "version" : "0.1.0",
"description" : "A Node-RED node that provides report-by-exception (RBE) and deadband capability.", "description" : "A Node-RED node that provides report-by-exception (RBE) and deadband capability.",
"dependencies" : { "dependencies" : {
}, },

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2014 IBM Corp. Copyright 2014, 2015 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -16,35 +16,36 @@
<script type="text/x-red" data-template-name="rbe"> <script type="text/x-red" data-template-name="rbe">
<div class="form-row"> <div class="form-row">
<label for="node-input-func"><i class="fa fa-wrench"></i> Mode</label> <label for="node-input-func"><i class="fa fa-wrench"></i> <span data-i18n="rbe.label.func"></span></label>
<select type="text" id="node-input-func" style="width:74%;"> <select type="text" id="node-input-func" style="width:74%;">
<option value="rbe">RBE - report if value changed</option> <option value="rbe" data-i18n="rbe.opts.rbe"></option>
<option value="deadband">Deadband - report if changed more than</option> <option value="deadband" data-i18n="rbe.opts.deadband"></option>
</select> </select>
</div> </div>
<div class="form-row" id="node-bandgap"> <div class="form-row" id="node-bandgap">
<label for="node-input-gap"><i class="fa fa-random"></i> Band gap</label> <label for="node-input-gap">&nbsp;</label>
<input type="text" id="node-input-gap" placeholder="e.g. 10 or 5%" style="width:71%;"> <input type="text" id="node-input-gap" data-i18n="[placeholder]rbe.placeholder.bandgap" style="width:71%;">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"/> Name</label> <label for="node-input-name"><i class="fa fa-tag"/> <span data-i18n="rbe.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name" style="width:71%;"> <input type="text" id="node-input-name" data-i18n="[placeholder]rbe.label.name" style="width:71%;">
</div> </div>
</script> </script>
<script type="text/x-red" data-help-name="rbe"> <script type="text/x-red" data-help-name="rbe">
<p>Report by Exception node - only passes on data if it has changed.</p> <p>Report by Exception node - only passes on data if it has changed.</p>
<p>In <b>RBE</b> mode this node only outputs the msg if the <b>msg.payload</b> is <p>The node can either block until the <b>msg.payload</b> is
different to the previous one. Works on numbers and strings.</p> different to the previous one - <b>rbe</b> mode. Works on numbers and strings.</p>
<p>In <b>deadband</b> mode the incoming payload should contain a parseable <i>number</i> and is <p>Or it can block until the value changes by a specified amount - <b>deadband</b> mode.</p>
<p>In deadband mode the incoming payload should contain a parseable <i>number</i> and is
output only if greater than + or - the <i>band gap</i> away from the previous output.</p> output only if greater than + or - the <i>band gap</i> away from the previous output.</p>
<p>Deadband also supports % - only sends if the input differs by more than x% of the original value.</p> <p>Deadband also supports % - only sends if the input differs by more than x% of the original value.</p>
<p><b>Note:</b> This works on a per <b>msg.topic</b> basis. This means that a single rbe node can <p><b>Note:</b> This works on a per <b>msg.topic</b> basis. This means that a single rbe node can
handle multiple topics at the same time.</p> handle multiple topics at the same time.</p>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
RED.nodes.registerType('rbe',{ RED.nodes.registerType("rbe", {
color:"#E2D96E", color:"#E2D96E",
category: 'function', category: 'function',
defaults: { defaults: {
@ -54,7 +55,7 @@ handle multiple topics at the same time.</p>
}, },
inputs:1, inputs:1,
outputs:1, outputs:1,
icon: "function.png", icon: "rbe.png",
label: function() { label: function() {
return this.name||this.func||"rbe"; return this.name||this.func||"rbe";
}, },

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2014 IBM Corp. * Copyright 2014, 2015 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,6 @@
module.exports = function(RED) { module.exports = function(RED) {
"use strict"; "use strict";
function RbeNode(n) { function RbeNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.func = n.func || "rbe"; this.func = n.func || "rbe";
@ -50,7 +49,7 @@ module.exports = function(RED) {
} }
} }
else { else {
node.warn("no number found in payload"); node.warn(RED._("rbe.warn.nonumber"));
} }
} }
} // ignore msg with no payload property. } // ignore msg with no payload property.

View File

@ -19,21 +19,21 @@
<input type="text" id="node-input-arduino"> <input type="text" id="node-input-arduino">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-pin"><i class="fa fa-circle"></i> Pin</label> <label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.pin"></span></label>
<input type="text" id="node-input-pin" placeholder="2"> <input type="text" id="node-input-pin" placeholder="2">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-state"><i class="fa fa-wrench"></i> Type</label> <label for="node-input-state"><i class="fa fa-wrench"></i> <span data-i18n="arduino.label.type"></span></label>
<select type="text" id="node-input-state" style="width: 150px;"> <select type="text" id="node-input-state" style="width: 150px;">
<option value="INPUT">Digital pin</option> <option value="INPUT" data-i18n="arduino.state.in.digital"></option>
<option value="ANALOG">Analogue pin</option> <option value="ANALOG" data-i18n="arduino.state.in.analogue"></option>
</select> </select>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<div class="form-tips"><b>Note:</b> You cannot use the same pin for both output and input.</div> <div class="form-tips"><span data-i18n="[html]arduino.tip.io"></span></div>
</script> </script>
<script type="text/x-red" data-help-name="arduino in"> <script type="text/x-red" data-help-name="arduino in">
@ -70,26 +70,26 @@
<script type="text/x-red" data-template-name="arduino out"> <script type="text/x-red" data-template-name="arduino out">
<div class="form-row"> <div class="form-row">
<label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label> <label for="node-input-arduino"><i class="fa fa-tasks"></i> <span data-i18n="arduino.label.arduino"></span></label>
<input type="text" id="node-input-arduino"> <input type="text" id="node-input-arduino">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-pin"><i class="fa fa-circle"></i> Pin</label> <label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.pin"></span></label>
<input type="text" id="node-input-pin" placeholder="13"> <input type="text" id="node-input-pin" placeholder="13">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-state"><i class="fa fa-wrench"></i> Type</label> <label for="node-input-state"><i class="fa fa-wrench"></i> <span data-i18n="arduino.label.type"></span></label>
<select type="text" id="node-input-state" style="width: 200px;"> <select type="text" id="node-input-state" style="width: 200px;">
<option value="OUTPUT">Digital (0/1)</option> <option value="OUTPUT" data-i18n="arduino.state.out.digital"></option>
<option value="PWM">Analogue (0-255)</option> <option value="PWM" data-i18n="arduino.state.out.analogue"></option>
<option value="SERVO">Servo (0-180)</option> <option value="SERVO" data-i18n="arduino.state.out.servo"></option>
</select> </select>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<div class="form-tips"><b>Note:</b> You cannot use the same pin for both output and input.</div> <div class="form-tips"><span data-i18n="[html]arduino.tip.io"></span></div>
</script> </script>
<script type="text/x-red" data-help-name="arduino out"> <script type="text/x-red" data-help-name="arduino out">
@ -124,11 +124,11 @@
<script type="text/x-red" data-template-name="arduino-board"> <script type="text/x-red" data-template-name="arduino-board">
<div class="form-row"> <div class="form-row">
<label for="node-config-input-device"><i class="fa fa-random"></i> Port</label> <label for="node-config-input-device"><i class="fa fa-random"></i> <span data-i18n="arduino.label.port"></span></label>
<input type="text" id="node-config-input-device" style="width:60%;" placeholder="e.g. /dev/ttyUSB0 COM1"/> <input type="text" id="node-config-input-device" style="width:60%;" data-i18n="[placeholder]arduino.placeholder.port"/>
<a id="node-config-lookup-serial" class="btn"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a> <a id="node-config-lookup-serial" class="btn"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a>
</div> </div>
<div class="form-tips"><b>Tip:</b> Use search to list serial ports, or leave blank to connect to first device found.</div> <div class="form-tips"><span data-i18n="[html]arduino.tip.conf"></span></div>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">

View File

@ -23,28 +23,30 @@ module.exports = function(RED) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.device = n.device || null; this.device = n.device || null;
this.repeat = n.repeat||25; this.repeat = n.repeat||25;
//node.log("opening connection "+this.device);
var node = this; var node = this;
node.board = new ArduinoFirmata(); node.board = new ArduinoFirmata();
// TODO: nls
ArduinoFirmata.list(function (err, ports) { ArduinoFirmata.list(function (err, ports) {
if (!node.device) { if (!node.device) {
node.log("connecting to first board found."); node.log(RED._("arduino.status.connectfirst"));
node.board.connect(); node.board.connect();
} }
else { else {
if (ports.indexOf(node.device) === -1) { if (ports.indexOf(node.device) === -1) {
node.warn(node.device + " not found. Trying to find board."); node.warn(RED._("arduino.errors.devnotfound",{dev:node.device}));
node.board.connect(); node.board.connect();
} }
else { else {
node.log("connecting to "+node.device); node.log(RED._("arduino.status.connect",{device:node.device}));
node.board.connect(node.device); node.board.connect(node.device);
} }
} }
node.board.on('boardReady', function() { node.board.on('boardReady', function() {
node.log("connected to "+node.board.serialport_name); node.log(RED._("arduino.status.connected",{device:node.board.serialport_name}));
if (RED.settings.verbose) { node.log("version "+node.board.boardVersion); } if (RED.settings.verbose) {
node.log(RED._("arduino.status.version",{version:node.board.boardVersion}));
}
}); });
}); });
@ -53,7 +55,7 @@ module.exports = function(RED) {
try { try {
node.board.close(function() { node.board.close(function() {
done(); done();
if (RED.settings.verbose) { node.log("port closed"); } if (RED.settings.verbose) { node.log(RED._("arduino.status.portclosed")); }
}); });
} catch(e) { done(); } } catch(e) { done(); }
} else { done(); } } else { done(); }
@ -73,9 +75,9 @@ module.exports = function(RED) {
if (typeof this.serverConfig === "object") { if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board; this.board = this.serverConfig.board;
var node = this; var node = this;
node.status({fill:"red",shape:"ring",text:"connecting"}); node.status({fill:"red",shape:"ring",text:"node-red:common.status.connecting"});
node.board.on('connect', function() { node.board.on('connect', function() {
node.status({fill:"green",shape:"dot",text:"connected"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
//console.log("i",node.state,node.pin); //console.log("i",node.state,node.pin);
if (node.state == "ANALOG") { if (node.state == "ANALOG") {
node.board.on('analogChange', function(e) { node.board.on('analogChange', function(e) {
@ -103,7 +105,7 @@ module.exports = function(RED) {
}); });
} }
else { else {
this.warn("port not configured"); this.warn(RED._("arduino.errors.portnotconf"));
} }
} }
RED.nodes.registerType("arduino in",DuinoNodeIn); RED.nodes.registerType("arduino in",DuinoNodeIn);
@ -120,10 +122,10 @@ module.exports = function(RED) {
if (typeof this.serverConfig === "object") { if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board; this.board = this.serverConfig.board;
var node = this; var node = this;
node.status({fill:"red",shape:"ring",text:"connecting"}); node.status({fill:"red",shape:"ring",text:"node-red:common.status.connecting"});
node.board.on('connect', function() { node.board.on('connect', function() {
node.status({fill:"green",shape:"dot",text:"connected"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
//console.log("o",node.state,node.pin); //console.log("o",node.state,node.pin);
node.board.pinMode(node.pin, node.state); node.board.pinMode(node.pin, node.state);
node.on("input", function(msg) { node.on("input", function(msg) {
@ -154,7 +156,7 @@ module.exports = function(RED) {
}); });
} }
else { else {
this.warn("port not configured"); this.warn(RED._("arduino.errors.portnotconf"));
} }
} }
RED.nodes.registerType("arduino out",DuinoNodeOut); RED.nodes.registerType("arduino out",DuinoNodeOut);

View File

@ -0,0 +1,38 @@
{
"arduino": {
"label": {
"pin": "Pin",
"type": "Type",
"port": "Port"
},
"placeholder": {
"port": "e.g. /dev/ttyUSB0 COM1"
},
"status": {
"connectfirst": "connecting to first board found",
"connect": "connecting to __device__",
"connected": "connected to __device__",
"version": "version: __version__",
"portclosed": "port closed"
},
"state": {
"in": {
"digital": "Digital pin",
"analogue": "Analogue pin"
},
"out": {
"digital": "Digital (0/1)",
"analogue": "Analogue (0-255)",
"servo": "Servo (0-180)"
}
},
"tip": {
"io": "<b>Note:</b> You cannot use the same pin for both output and input.",
"conf": "<b>Tip:</b> Use search to try to auto-detect serial port."
},
"errors": {
"portnotconf": "port not configured",
"devnotfound": "device __dev__ not found. Trying to find board."
}
}
}

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2013,2015 IBM Corp. Copyright 2013,2014 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -16,20 +16,20 @@
<script type="text/x-red" data-template-name="serial in"> <script type="text/x-red" data-template-name="serial in">
<div class="form-row node-input-serial"> <div class="form-row node-input-serial">
<label for="node-input-serial"><i class="fa fa-random"></i> Serial Port</label> <label for="node-input-serial"><i class="fa fa-random"></i> <span data-i18n="serial.label.serialport"></span></label>
<input type="text" id="node-input-serial"> <input type="text" id="node-input-serial">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
</script> </script>
<script type="text/x-red" data-help-name="serial in"> <script type="text/x-red" data-help-name="serial in">
<p>Reads data from a local serial port.</p> <p>Reads data from a local serial port.</p>
<p>Can either <ul><li>wait for a "split" character (default \n). Also accepts hex notation (0x0a).</li> <p>Can either <ul><li>wait for a "split" character (default \n). Also accepts hex notation (0x0a).</li>
<li>wait for a timeout in milliseconds for the first character received</li> <li>Wait for a timeout in milliseconds for the first character received</li>
<li>wait to fill a fixed sized buffer</li></ul></p> <li>Wait to fill a fixed sized buffer</li></ul></p>
<p>It then outputs <b>msg.payload</b> as either a UTF8 ascii string or a binary Buffer object.</p> <p>It then outputs <b>msg.payload</b> as either a UTF8 ascii string or a binary Buffer object.</p>
<p>If no split character is specified, or a timeout or buffer size of 0, then a stream of single characters is sent - again either as ascii chars or size 1 binary buffers.</p> <p>If no split character is specified, or a timeout or buffer size of 0, then a stream of single characters is sent - again either as ascii chars or size 1 binary buffers.</p>
</script> </script>
@ -47,7 +47,7 @@
icon: "serial.png", icon: "serial.png",
label: function() { label: function() {
var serialNode = RED.nodes.node(this.serial); var serialNode = RED.nodes.node(this.serial);
return this.name||(serialNode?serialNode.label().split(":")[0]:"serial"); return this.name||(serialNode?serialNode.label().split(":")[0]:this._("serial.label.serial"));
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
@ -57,12 +57,12 @@
<script type="text/x-red" data-template-name="serial out"> <script type="text/x-red" data-template-name="serial out">
<div class="form-row node-input-serial"> <div class="form-row node-input-serial">
<label for="node-input-serial"><i class="fa fa-random"></i> Serial Port</label> <label for="node-input-serial"><i class="fa fa-random"></i> <span data-i18n="serial.label.serialport"></span></label>
<input type="text" id="node-input-serial"> <input type="text" id="node-input-serial">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
</script> </script>
@ -86,7 +86,7 @@
align: "right", align: "right",
label: function() { label: function() {
var serialNode = RED.nodes.node(this.serial); var serialNode = RED.nodes.node(this.serial);
return this.name||(serialNode?serialNode.label().split(":")[0]:"serial"); return this.name||(serialNode?serialNode.label().split(":")[0]:this._("serial.label.serial"));
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
@ -97,17 +97,17 @@
<script type="text/x-red" data-template-name="serial-port"> <script type="text/x-red" data-template-name="serial-port">
<div class="form-row"> <div class="form-row">
<label for="node-config-input-serialport"><i class="fa fa-random"></i> Serial Port</label> <label for="node-config-input-serialport"><i class="fa fa-random"></i> <span data-i18n="serial.label.serialport"></span></label>
<input type="text" id="node-config-input-serialport" style="width:60%;" placeholder="/dev/ttyUSB0"/> <input type="text" id="node-config-input-serialport" style="width:60%;" data-i18n="[placeholder]serial.placeholder.serialport">
<a id="node-config-lookup-serial" class="btn"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a> <a id="node-config-lookup-serial" class="btn"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a>
</div> </div>
<div class="form-row"> <div class="form-row">
<table><tr> <table><tr>
<td width="102px"><i class="fa fa-wrench"></i> Settings</td> <td width="102px"><i class="fa fa-wrench"></i> <span data-i18n="serial.label.settings"></span></td>
<td width="100px">Baud Rate</td> <td width="100px" data-i18n="serial.label.baudrate"></td>
<td width="80px">Data Bits</td> <td width="80px" data-i18n="serial.label.databits"></td>
<td width="80px">Parity</td> <td width="80px" data-i18n="serial.label.parity"></td>
<td width="80px">Stop Bits</td> <td width="80px" data-i18n="serial.label.stopbits"></td>
</tr><tr><td>&nbsp;</td> </tr><tr><td>&nbsp;</td>
<td> <td>
<select type="text" id="node-config-input-serialbaud" style="width: 100px;"> <select type="text" id="node-config-input-serialbaud" style="width: 100px;">
@ -138,11 +138,11 @@
</select> </select>
</td><td> </td><td>
<select type="text" id="node-config-input-parity" style="width: 80px;"> <select type="text" id="node-config-input-parity" style="width: 80px;">
<option value="none">None</option> <option value="none" data-i18n="serial.parity.none"></option>
<option value="even">Even</option> <option value="even" data-i18n="serial.parity.even"></option>
<option value="mark">Mark</option> <option value="mark" data-i18n="serial.parity.mark"></option>
<option value="odd">Odd</option> <option value="odd" data-i18n="serial.parity.odd"></option>
<option value="space">Space</option> <option value="space" data-i18n="serial.parity.space"></option>
</select> </select>
</td><td> </td><td>
<select type="text" id="node-config-input-stopbits" style="width: 80px;"> <select type="text" id="node-config-input-stopbits" style="width: 80px;">
@ -153,36 +153,36 @@
</tr></table><br/> </tr></table><br/>
<div class="form-row"> <div class="form-row">
<label><i class="fa fa-sign-in"></i> Input</label> <label><i class="fa fa-sign-in"></i> <span data-i18n="serial.label.input"></span></label>
</div> </div>
<div class="form-row" style="padding-left: 10px;"> <div class="form-row" style="padding-left: 10px;">
Split input <span data-i18n="serial.label.split"></span>
<select type="text" id="node-config-input-out" style="margin-left: 5px; width:200px;"> <select type="text" id="node-config-input-out" style="margin-left: 5px; width:200px;">
<option value="char">on the character</option> <option value="char" data-i18n="serial.split.character"></option>
<option value="time">after a timeout of</option> <option value="time" data-i18n="serial.split.timeout"></option>
<option value="count">into fixed lengths of</option> <option value="count" data-i18n="serial.split.lengths"></option>
</select> </select>
<input type="text" id="node-config-input-newline" style="width:50px;"> <input type="text" id="node-config-input-newline" style="width:50px;">
<span id="node-units"></span> <span id="node-units"></span>
</div> </div>
<div class="form-row" style="padding-left: 10px;"> <div class="form-row" style="padding-left: 10px;">
and deliver <span data-i18n="serial.label.deliver"></span>
<select type="text" id="node-config-input-bin" style="margin-left: 5px; width: 150px;"> <select type="text" id="node-config-input-bin" style="margin-left: 5px; width: 150px;">
<option value="false">ascii strings</option> <option value="false" data-i18n="serial.output.ascii"></option>
<option value="bin">binary buffers</option> <option value="bin" data-i18n="serial.output.binary"></option>
</select> </select>
</div> </div>
<br/> <br/>
<div id="node-config-addchar"> <div id="node-config-addchar">
<div class="form-row"> <div class="form-row">
<label><i class="fa fa-sign-out"></i> Output</label> <label><i class="fa fa-sign-out"></i> <span data-i18n="serial.label.output"></span></label>
</div> </div>
<div class="form-row"> <div class="form-row">
<input style="width: 30px;margin-left: 10px; vertical-align: top;" type="checkbox" id="node-config-input-addchar"><label style="width: auto;" for="node-config-input-addchar">add split character to output messages</label> <input style="width: 30px;margin-left: 10px; vertical-align: top;" type="checkbox" id="node-config-input-addchar"><label style="width: auto;" for="node-config-input-addchar"><span data-i18n="serial.addsplit"></span></label>
</div> </div>
</div> </div>
<div class="form-tips" id="tip-split">Tip: the "Split on" character is used to split the input into separate messages. It can also be added to every message sent out to the serial port.</div> <div class="form-tips" id="tip-split"><span data-i18n="serial.tip.split"></span></div>
<div class="form-tips" id="tip-bin" hidden>Tip: In timeout mode timeout starts from arrival of first character.</div> <div class="form-tips" id="tip-bin" hidden><span data-i18n="serial.tip.timeout"></span></div>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
@ -203,7 +203,7 @@
label: function() { label: function() {
this.serialbaud = this.serialbaud || 57600; this.serialbaud = this.serialbaud || 57600;
this.databits = this.databits || 8; this.databits = this.databits || 8;
this.parity = this.parity || 'none'; this.parity = this.parity || this._("serial.label.none");
this.stopbits = this.stopbits || 1; this.stopbits = this.stopbits || 1;
return this.serialport+":"+this.serialbaud+"-"+this.databits+this.parity.charAt(0).toUpperCase()+this.stopbits; return this.serialport+":"+this.serialbaud+"-"+this.databits+this.parity.charAt(0).toUpperCase()+this.stopbits;
}, },

View File

@ -76,13 +76,13 @@ module.exports = function(RED) {
} }
}); });
node.port.on('ready', function() { node.port.on('ready', function() {
node.status({fill:"green",shape:"dot",text:"connected"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
}); });
node.port.on('closed', function() { node.port.on('closed', function() {
node.status({fill:"red",shape:"ring",text:"not connected"}); node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"});
}); });
} else { } else {
this.error("missing serial config"); this.error(RED._("serial.errors.missing-conf"));
} }
this.on("close", function(done) { this.on("close", function(done) {
@ -108,7 +108,7 @@ module.exports = function(RED) {
if (node.serialConfig.out != "count") { buf = new Buffer(bufMaxSize); } if (node.serialConfig.out != "count") { buf = new Buffer(bufMaxSize); }
else { buf = new Buffer(Number(node.serialConfig.newline)); } else { buf = new Buffer(Number(node.serialConfig.newline)); }
var i = 0; var i = 0;
node.status({fill:"grey",shape:"dot",text:"unknown"}); node.status({fill:"grey",shape:"dot",text:"node-red:common.status.not-connected"});
node.port = serialPool.get(this.serialConfig.serialport, node.port = serialPool.get(this.serialConfig.serialport,
this.serialConfig.serialbaud, this.serialConfig.serialbaud,
this.serialConfig.databits, this.serialConfig.databits,
@ -176,17 +176,16 @@ module.exports = function(RED) {
i = 0; i = 0;
} }
} }
else { node.log("should never get here"); }
} }
}); });
this.port.on('ready', function() { this.port.on('ready', function() {
node.status({fill:"green",shape:"dot",text:"connected"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
}); });
this.port.on('closed', function() { this.port.on('closed', function() {
node.status({fill:"red",shape:"ring",text:"not connected"}); node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"});
}); });
} else { } else {
this.error("missing serial config"); this.error(RED._("serial.errors.missing-conf"));
} }
this.on("close", function(done) { this.on("close", function(done) {
@ -226,7 +225,7 @@ module.exports = function(RED) {
parser: serialp.parsers.raw parser: serialp.parsers.raw
},true, function(err, results) { if (err) { obj.serial.emit('error',err); } }); },true, function(err, results) { if (err) { obj.serial.emit('error',err); } });
obj.serial.on('error', function(err) { obj.serial.on('error', function(err) {
RED.log.error("serial port "+port+" error "+err); RED.log.error(RED._("serial.errors.error",{port:port,error:err.toString()}));
obj._emitter.emit('closed'); obj._emitter.emit('closed');
obj.tout = setTimeout(function() { obj.tout = setTimeout(function() {
setupSerial(); setupSerial();
@ -234,7 +233,7 @@ module.exports = function(RED) {
}); });
obj.serial.on('close', function() { obj.serial.on('close', function() {
if (!obj._closing) { if (!obj._closing) {
RED.log.error("serial port "+port+" closed unexpectedly"); RED.log.error(RED._("serial.errors.unexpected-close",{port:port}));
obj._emitter.emit('closed'); obj._emitter.emit('closed');
obj.tout = setTimeout(function() { obj.tout = setTimeout(function() {
setupSerial(); setupSerial();
@ -242,7 +241,7 @@ module.exports = function(RED) {
} }
}); });
obj.serial.on('open',function() { obj.serial.on('open',function() {
RED.log.info("serial port "+port+" opened at "+baud+" baud "+databits+""+parity.charAt(0).toUpperCase()+stopbits); RED.log.info(RED._("serial.onopen",{port:port,baud:baud,config: databits+""+parity.charAt(0).toUpperCase()+stopbits}));
if (obj.tout) { clearTimeout(obj.tout); } if (obj.tout) { clearTimeout(obj.tout); }
//obj.serial.flush(); //obj.serial.flush();
obj._emitter.emit('ready'); obj._emitter.emit('ready');
@ -253,7 +252,7 @@ module.exports = function(RED) {
} }
}); });
obj.serial.on("disconnect",function() { obj.serial.on("disconnect",function() {
RED.log.error("serial port "+port+" gone away"); RED.log.error(RED._("serial.errors.disconnected",{port:port}));
}); });
} }
setupSerial(); setupSerial();
@ -270,7 +269,7 @@ module.exports = function(RED) {
connections[port]._closing = true; connections[port]._closing = true;
try { try {
connections[port].close(function() { connections[port].close(function() {
RED.log.info("serial port closed"); RED.log.info(RED._("serial.errors.closed",{port:port}));
done(); done();
}); });
} }

View File

@ -0,0 +1,51 @@
{
"serial": {
"label": {
"serialport": "Serial Port",
"settings": "Settings",
"baudrate": "Baud Rate",
"databits": "Data Bits",
"parity": "Parity",
"stopbits": "Stop Bits",
"input": "Input",
"split": "Split input",
"deliver": "and deliver",
"output": "Output",
"serial": "serial",
"none": "none"
},
"placeholder": {
"serialport": "for example: /dev/ttyUSB0/"
},
"parity": {
"none": "None",
"even": "Even",
"mark": "Mark",
"odd": "Odd",
"space": "Space"
},
"split": {
"character": "on the character",
"timeout": "after a timeout of",
"lengths": "into fixed lengths of"
},
"output": {
"ascii": "ascii strings",
"binary": "binary buffers"
},
"addsplit": "add split character to output messages",
"tip": {
"split": "Tip: the \"Split on\" character is used to split the input into separate messages. It can also be added to every message sent out to the serial port.",
"timeout": "Tip: In timeout mode timeout starts from arrival of first character."
},
"onopen": "serial port __port__ opened at __baud__ baud __config__",
"errors": {
"missing-conf": "missing serial config",
"serial-port": "serial port",
"error": "serial port __port__ error: __error__",
"unexpected-close": "serial port __port__ closed unexpectedly",
"disconnected": "serial port __port__ disconnected",
"closed": "serial port __port__ closed"
}
}
}

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2013,2014 IBM Corp. Copyright 2013, 2015 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -16,7 +16,7 @@
<script type="text/x-red" data-template-name="e-mail"> <script type="text/x-red" data-template-name="e-mail">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-envelope"></i> To</label> <label for="node-input-name"><i class="fa fa-envelope"></i> <span data-i18n="email.label.to"></span></label>
<input type="text" id="node-input-name" placeholder="email@address.com"> <input type="text" id="node-input-name" placeholder="email@address.com">
</div> </div>
<!-- <div class="form-row"> <!-- <div class="form-row">
@ -45,27 +45,27 @@
</select> </select>
</div> --> </div> -->
<div class="form-row"> <div class="form-row">
<label for="node-input-server"><i class="fa fa-globe"></i> Server</label> <label for="node-input-server"><i class="fa fa-globe"></i> <span data-i18n="email.label.server"></span></label>
<input type="text" id="node-input-server" placeholder="smtp.gmail.com"> <input type="text" id="node-input-server" placeholder="smtp.gmail.com">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-port"><i class="fa fa-random"></i> Port</label> <label for="node-input-port"><i class="fa fa-random"></i> <span data-i18n="email.label.port"></span></label>
<input type="text" id="node-input-port" placeholder="465"> <input type="text" id="node-input-port" placeholder="465">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-userid"><i class="fa fa-user"></i> Userid</label> <label for="node-input-userid"><i class="fa fa-user"></i> <span data-i18n="email.label.userid"></span></label>
<input type="text" id="node-input-userid"> <input type="text" id="node-input-userid">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-password"><i class="fa fa-lock"></i> Password</label> <label for="node-input-password"><i class="fa fa-lock"></i> <span data-i18n="email.label.password"></span></label>
<input type="password" id="node-input-password"> <input type="password" id="node-input-password">
</div> </div>
<br/> <br/>
<div class="form-row"> <div class="form-row">
<label for="node-input-dname"><i class="fa fa-tag"></i> Name</label> <label for="node-input-dname"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-dname" placeholder="Name"> <input type="text" id="node-input-dname" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<div class="form-tips" id="node-tip"><b>Note:</b> Copied credentials from global emailkeys.js file.</div> <div class="form-tips" id="node-tip"><span data-i18n="[html]email.tip.cred"></span></div>
</script> </script>
<script type="text/x-red" data-help-name="e-mail"> <script type="text/x-red" data-help-name="e-mail">
@ -119,36 +119,36 @@
<script type="text/x-red" data-template-name="e-mail in"> <script type="text/x-red" data-template-name="e-mail in">
<div class="form-row node-input-repeat"> <div class="form-row node-input-repeat">
<label for="node-input-repeat"><i class="fa fa-repeat"></i> Check Repeat (S)</label> <label for="node-input-repeat"><i class="fa fa-repeat"></i> <span data-i18n="email.label.repeat"></span></label>
<input type="text" id="node-input-repeat" placeholder="300"> <input type="text" id="node-input-repeat" style="width: 80px"> <span data-i18n="email.label.seconds">seconds</span>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-server"><i class="fa fa-globe"></i> Server</label> <label for="node-input-server"><i class="fa fa-globe"></i> <span data-i18n="email.label.server"></span></label>
<input type="text" id="node-input-server" placeholder="imap.gmail.com"> <input type="text" id="node-input-server" placeholder="imap.gmail.com">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-port"><i class="fa fa-random"></i> Port</label> <label for="node-input-port"><i class="fa fa-random"></i> <span data-i18n="email.label.port"></span></label>
<input type="text" id="node-input-port" placeholder="993"> <input type="text" id="node-input-port" placeholder="993">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-userid"><i class="fa fa-user"></i> Userid</label> <label for="node-input-userid"><i class="fa fa-user"></i> <span data-i18n="email.label.userid"></span></label>
<input type="text" id="node-input-userid"> <input type="text" id="node-input-userid">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-password"><i class="fa fa-lock"></i> Password</label> <label for="node-input-password"><i class="fa fa-lock"></i> <span data-i18n="email.label.password"></span></label>
<input type="password" id="node-input-password"> <input type="password" id="node-input-password">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-box"><i class="fa fa-inbox"></i> Folder</label> <label for="node-input-box"><i class="fa fa-inbox"></i> <span data-i18n="email.label.folder"></span></label>
<input type="text" id="node-input-box"> <input type="text" id="node-input-box">
</div> </div>
<br/> <br/>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<div class="form-tips" id="node-tip"><b>Note:</b> Copied credentials from global emailkeys.js file.</div> <div class="form-tips" id="node-tip"><span data-i18n="[html]email.tip.cred"></span></div>
<div id="node-input-tip" class="form-tips">Tip: <b>ONLY</b> retrieves the single most recent email.</div> <div id="node-input-tip" class="form-tips"><span data-i18n="[html]email.tip.recent"></span></div>
</script> </script>
<script type="text/x-red" data-help-name="e-mail in"> <script type="text/x-red" data-help-name="e-mail in">

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2013,2014 IBM Corp. * Copyright 2013, 2015 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -40,7 +40,7 @@ module.exports = function(RED) {
this.userid = globalkeys.user; this.userid = globalkeys.user;
flag = true; flag = true;
} else { } else {
this.error("No e-mail userid set"); this.error(RED._("email.errors.nouserid"));
} }
} }
if (this.credentials && this.credentials.hasOwnProperty("password")) { if (this.credentials && this.credentials.hasOwnProperty("password")) {
@ -50,7 +50,7 @@ module.exports = function(RED) {
this.password = globalkeys.pass; this.password = globalkeys.pass;
flag = true; flag = true;
} else { } else {
this.error("No e-mail password set"); this.error(RED._("email.errors.nopassword"));
} }
} }
if (flag) { if (flag) {
@ -71,9 +71,9 @@ module.exports = function(RED) {
this.on("input", function(msg) { this.on("input", function(msg) {
if (msg.hasOwnProperty("payload")) { if (msg.hasOwnProperty("payload")) {
if (smtpTransport) { if (smtpTransport) {
node.status({fill:"blue",shape:"dot",text:"sending"}); node.status({fill:"blue",shape:"dot",text:"email.status.sending"});
if (msg.to && node.name && (msg.to !== node.name)) { if (msg.to && node.name && (msg.to !== node.name)) {
node.warn("Warning: msg properties can no longer override set node properties. See bit.ly/nr-override-msg-props"); node.warn(RED._("node-red:common.errors.nooverride"));
} }
var sendopts = { from: node.userid }; // sender address var sendopts = { from: node.userid }; // sender address
sendopts.to = node.name || msg.to; // comma separated list of addressees sendopts.to = node.name || msg.to; // comma separated list of addressees
@ -92,7 +92,7 @@ module.exports = function(RED) {
sendopts.attachments[0].contentType = msg.headers["content-type"]; sendopts.attachments[0].contentType = msg.headers["content-type"];
} }
// Create some body text.. // Create some body text..
sendopts.text = "Your file from Node-RED is attached : "+(msg.filename.replace(/^.*[\\\/]/, '') || "file.bin")+ (msg.hasOwnProperty("description") ? "\n\n"+msg.description : ""); sendopts.text = RED._("email.default-message",{filename:(msg.filename.replace(/^.*[\\\/]/, '') || "file.bin"),description:(msg.hasOwnProperty("description") ? "\n\n"+msg.description : "")});
} }
else { else {
var payload = RED.util.ensureString(msg.payload); var payload = RED.util.ensureString(msg.payload);
@ -103,16 +103,16 @@ module.exports = function(RED) {
smtpTransport.sendMail(sendopts, function(error, info) { smtpTransport.sendMail(sendopts, function(error, info) {
if (error) { if (error) {
node.error(error,msg); node.error(error,msg);
node.status({fill:"red",shape:"ring",text:"send failed"}); node.status({fill:"red",shape:"ring",text:"email.status.sendfail"});
} else { } else {
node.log("Message sent: " + info.response); node.log(RED._("email.status.messagesent",{response:info.response}));
node.status({}); node.status({});
} }
}); });
} }
else { node.warn("No Email credentials found. See info panel."); } else { node.warn(RED._("email.errors.nocredentials")); }
} }
else { node.warn("No payload to send"); } else { node.warn(RED._("email.errors.nopayload")); }
}); });
} }
RED.nodes.registerType("e-mail",EmailNode,{ RED.nodes.registerType("e-mail",EmailNode,{
@ -139,7 +139,7 @@ module.exports = function(RED) {
this.userid = globalkeys.user; this.userid = globalkeys.user;
flag = true; flag = true;
} else { } else {
this.error("No e-mail userid set"); this.error(RED._("email.errors.nouserid"));
} }
} }
if (this.credentials && this.credentials.hasOwnProperty("password")) { if (this.credentials && this.credentials.hasOwnProperty("password")) {
@ -149,7 +149,7 @@ module.exports = function(RED) {
this.password = globalkeys.pass; this.password = globalkeys.pass;
flag = true; flag = true;
} else { } else {
this.error("No e-mail password set"); this.error(RED._("email.errors.nopassword"));
} }
} }
if (flag) { if (flag) {
@ -172,7 +172,6 @@ module.exports = function(RED) {
}); });
if (!isNaN(this.repeat) && this.repeat > 0) { if (!isNaN(this.repeat) && this.repeat > 0) {
node.log("repeat = "+this.repeat);
this.interval_id = setInterval( function() { this.interval_id = setInterval( function() {
node.emit("input",{}); node.emit("input",{});
}, this.repeat ); }, this.repeat );
@ -180,19 +179,19 @@ module.exports = function(RED) {
this.on("input", function(msg) { this.on("input", function(msg) {
imap.once('ready', function() { imap.once('ready', function() {
node.status({fill:"blue",shape:"dot",text:"fetching"}); node.status({fill:"blue",shape:"dot",text:"email.status.fetching"});
var pay = {}; var pay = {};
imap.openBox(node.box, false, function(err, box) { imap.openBox(node.box, false, function(err, box) {
if (err) { if (err) {
node.status({fill:"red",shape:"ring",text:"fetch folder error"}); node.status({fill:"red",shape:"ring",text:"email.status.foldererror"});
node.error("Failed to fetch folder "+node.box,err); node.error(RED._("email.errors.fetchfail",{folder:node.box}),err);
} }
else { else {
if (box.messages.total > 0) { if (box.messages.total > 0) {
//var f = imap.seq.fetch(box.messages.total + ':*', { markSeen:true, bodies: ['HEADER.FIELDS (FROM SUBJECT DATE TO CC BCC)','TEXT'] }); //var f = imap.seq.fetch(box.messages.total + ':*', { markSeen:true, bodies: ['HEADER.FIELDS (FROM SUBJECT DATE TO CC BCC)','TEXT'] });
var f = imap.seq.fetch(box.messages.total + ':*', { markSeen:true, bodies: ['HEADER','TEXT'] }); var f = imap.seq.fetch(box.messages.total + ':*', { markSeen:true, bodies: ['HEADER','TEXT'] });
f.on('message', function(msg, seqno) { f.on('message', function(msg, seqno) {
node.log('message: #'+ seqno); node.log(RED._("email.status.message",{number:seqno}));
var prefix = '(#' + seqno + ') '; var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) { msg.on('body', function(stream, info) {
var buffer = ''; var buffer = '';
@ -210,62 +209,54 @@ module.exports = function(RED) {
var parts = buffer.split("Content-Type"); var parts = buffer.split("Content-Type");
for (var p = 0; p < parts.length; p++) { for (var p = 0; p < parts.length; p++) {
if (parts[p].indexOf("text/plain") >= 0) { if (parts[p].indexOf("text/plain") >= 0) {
console.log("TEXT");
pay.payload = parts[p].split("\n").slice(1,-2).join("\n").trim(); pay.payload = parts[p].split("\n").slice(1,-2).join("\n").trim();
} }
else if (parts[p].indexOf("text/html") >= 0) { else if (parts[p].indexOf("text/html") >= 0) {
console.log("HTML");
pay.html = parts[p].split("\n").slice(1,-2).join("\n").trim(); pay.html = parts[p].split("\n").slice(1,-2).join("\n").trim();
} else { } else {
console.log("OTHER");
pay.payload = parts[0]; pay.payload = parts[0];
} }
console.log("***",pay.payload,"***");
} }
//pay.body = buffer; //pay.body = buffer;
} }
}); });
}); });
msg.on('end', function() { msg.on('end', function() {
//node.log('Finished: '+prefix); //node.log('finished: '+prefix);
}); });
}); });
f.on('error', function(err) { f.on('error', function(err) {
node.warn('fetch message error: ' + err); node.warn(RED._("email.errors.messageerror",{error:err}));
node.status({fill:"red",shape:"ring",text:"fetch message error"}); node.status({fill:"red",shape:"ring",text:"email.status.messageerror"});
}); });
f.on('end', function() { f.on('end', function() {
delete(pay._msgid); delete(pay._msgid);
if (JSON.stringify(pay) !== oldmail) { if (JSON.stringify(pay) !== oldmail) {
oldmail = JSON.stringify(pay); oldmail = JSON.stringify(pay);
node.send(pay); node.send(pay);
node.log('received new email: '+pay.topic); node.log(RED._("email.status.newemail",{topic:pay.topic}));
} }
else { node.log('duplicate not sent: '+pay.topic); } else { node.log(RED._("email.status.duplicate",{topic:pay.topic})); }
//node.status({fill:"green",shape:"dot",text:"ok"}); //node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"});
node.status({}); node.status({});
}); });
} }
else { else {
node.log("you have achieved inbox zero"); node.log(RED._("email.status.inboxzero"));
//node.status({fill:"green",shape:"dot",text:"ok"}); //node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"});
node.status({}); node.status({});
} }
} }
imap.end(); imap.end();
}); });
}); });
node.status({fill:"grey",shape:"dot",text:"connecting"}); node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
imap.connect(); imap.connect();
}); });
imap.on('error', function(err) { imap.on('error', function(err) {
node.log(err); node.log(err);
node.status({fill:"red",shape:"ring",text:"connect error"}); node.status({fill:"red",shape:"ring",text:"email.status.connecterror"});
});
this.on("error", function(err) {
node.log("error: ",err);
}); });
this.on("close", function() { this.on("close", function() {

View File

@ -0,0 +1,43 @@
{
"email": {
"label": {
"to": "To",
"server": "Server",
"port": "Port",
"userid": "Userid",
"password": "Password",
"repeat": "Refresh",
"seconds": "seconds",
"folder": "Folder"
},
"default-message": "Your file from Node-RED is attached: __filename__ __description__",
"tip": {
"cred": "<b>Note:</b> Copied credentials from global emailkeys.js file.",
"recent": "Tip: Only retrieves the single most recent email."
},
"status": {
"messagesent": "Message sent: __response__",
"fetching": "fetching",
"foldererror": "fetch folder error",
"messageerror": "fetch message error",
"message": "message #__number__",
"newemail": "received new email: __topic__",
"duplicate": "duplicate not sent: __topic__",
"inboxzero": "you have achieved Inbox Zero",
"sending": "sending",
"sendfail": "send failed",
"connecterror": "connect error"
},
"errors": {
"nouserid": "No e-mail userid set",
"nopassword": "No e-mail password set",
"nocredentials": "No Email credentials found. See info panel.",
"nopayload": "No payload to send",
"fetchfail": "Failed to fetch folder: __folder__",
"messageerror": "Fetch message error: __error__"
}
}
}

View File

@ -1,6 +1,6 @@
{ {
"name" : "node-red-node-email", "name" : "node-red-node-email",
"version" : "0.0.5", "version" : "0.1.0",
"description" : "Node-RED nodes to send and receive simple emails", "description" : "Node-RED nodes to send and receive simple emails",
"dependencies" : { "dependencies" : {
"nodemailer" : "1.3.4", "nodemailer" : "1.3.4",

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2013 IBM Corp. Copyright 2013, 2015 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -16,18 +16,17 @@
<script type="text/x-red" data-template-name="feedparse"> <script type="text/x-red" data-template-name="feedparse">
<div class="form-row"> <div class="form-row">
<label for="node-input-url"><i class="fa fa-globe"></i> Feed url</label> <label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="feedparse.label.feedurl"></span></label>
<input type="text" id="node-input-url"> <input type="text" id="node-input-url">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-interval"><i class="fa fa-repeat"></i> Repeat <span style="font-size: 0.9em;">(M)</span></label> <label for="node-input-interval"><i class="fa fa-repeat"></i> <span data-i18n="feedparse.label.refresh"></span></label>
<input type="text" id="node-input-interval" placeholder="minutes"> <input type="text" id="node-input-interval" style="width: 50px"> <span data-i18n="feedparse.label.minutes"></span>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<!-- <div class="form-tips"></div> -->
</script> </script>
<script type="text/x-red" data-help-name="feedparse"> <script type="text/x-red" data-help-name="feedparse">

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2013,2014 IBM Corp. * Copyright 2013, 2015 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,7 +38,7 @@ module.exports = function(RED) {
req.on('error', function(err) { node.error(err); }); req.on('error', function(err) { node.error(err); });
req.on('response', function(res) { req.on('response', function(res) {
if (res.statusCode != 200) { node.warn('error - Bad status code'); } if (res.statusCode != 200) { node.warn(RED._("feedparse.errors.badstatuscode")); }
else { res.pipe(feedparser); } else { res.pipe(feedparser); }
}); });
@ -65,7 +65,7 @@ module.exports = function(RED) {
this.interval_id = setInterval(function() { getFeed(); }, node.interval); this.interval_id = setInterval(function() { getFeed(); }, node.interval);
getFeed(); getFeed();
} else { } else {
this.error("Invalid url"); this.error(RED._("feedparse.errors.invalidurl"));
} }
this.on("close", function() { this.on("close", function() {

View File

@ -0,0 +1,13 @@
{
"feedparse": {
"label": {
"feedurl": "Feed url",
"refresh": "Refresh",
"minutes": "minutes"
},
"errors": {
"badstatuscode": "error - Bad status code",
"invalidurl": "Invalid url"
}
}
}

View File

@ -1,6 +1,6 @@
{ {
"name" : "node-red-node-feedparser", "name" : "node-red-node-feedparser",
"version" : "0.0.4", "version" : "0.1.0",
"description" : "A Node-RED node to get RSS Atom feeds.", "description" : "A Node-RED node to get RSS Atom feeds.",
"dependencies" : { "dependencies" : {
"feedparser" : "0.19.2", "feedparser" : "0.19.2",

View File

@ -16,19 +16,18 @@
<script type="text/x-red" data-template-name="irc in"> <script type="text/x-red" data-template-name="irc in">
<div class="form-row"> <div class="form-row">
<label for="node-input-ircserver"><i class="fa fa-globe"></i> IRC Server</label> <label for="node-input-ircserver"><i class="fa fa-globe"></i> <span data-i18n="irc.label.ircserver"></span></label>
<input type="text" id="node-input-ircserver"> <input type="text" id="node-input-ircserver">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-channel"><i class="fa fa-random"></i> Channel</label> <label for="node-input-channel"><i class="fa fa-random"></i> <span data-i18n="irc.label.channel"></span></label>
<input type="text" id="node-input-channel" placeholder="#nodered"> <input type="text" id="node-input-channel" placeholder="#nodered">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<div class="form-tips">The channel to join must start with a # (as per normal irc rules...)<br/> <div class="form-tips"><span data-i18n="[html]irc.tip.in"></span></div>
You may join multiple channels by comma separating a list - #chan1,#chan2,etc.</div>
</script> </script>
<script type="text/x-red" data-help-name="irc in"> <script type="text/x-red" data-help-name="irc in">
@ -118,27 +117,26 @@
<script type="text/x-red" data-template-name="irc out"> <script type="text/x-red" data-template-name="irc out">
<div class="form-row"> <div class="form-row">
<label for="node-input-ircserver"><i class="fa fa-globe"></i> IRC Server</label> <label for="node-input-ircserver"><i class="fa fa-globe"></i> <span data-i18n="irc.label.ircserver"></span></label>
<input type="text" id="node-input-ircserver"> <input type="text" id="node-input-ircserver">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-channel"><i class="fa fa-random"></i> Channel</label> <label for="node-input-channel"><i class="fa fa-random"></i> <span data-i18n="irc.label.channel"></span></label>
<input type="text" id="node-input-channel" placeholder="#nodered"> <input type="text" id="node-input-channel" placeholder="#nodered">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-sendObject"><i class="fa fa-arrows"></i> Action</label> <label for="node-input-sendObject"><i class="fa fa-arrows"></i> <span data-i18n="irc.label.action"></span></label>
<select type="text" id="node-input-sendObject" style="display: inline-block; vertical-align: middle; width:70%;"> <select type="text" id="node-input-sendObject" style="display: inline-block; vertical-align: middle; width:70%;">
<option value="pay">Send payload to channel(s)</option> <option value="pay" data-i18n="irc.payload"></option>
<option value="true">Use msg.topic to set nickname or channel(s)</option> <option value="true" data-i18n="irc.topic"></option>
<option value="false">Send complete msg object to channel(s)</option> <option value="false" data-i18n="irc.msg"></option>
</select> </select>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<div class="form-tips">The channel to join must start with a # (as per normal irc rules...)<br/> <div class="form-tips"><span data-i18n="[html]irc.tip.out"></span></div>
Sending the complete object will stringify the whole msg object before sending.</div>
</script> </script>
<script type="text/x-red" data-help-name="irc out"> <script type="text/x-red" data-help-name="irc out">
@ -183,24 +181,24 @@
<script type="text/x-red" data-template-name="irc-server"> <script type="text/x-red" data-template-name="irc-server">
<div class="form-row"> <div class="form-row">
<label for="node-config-input-server"><i class="fa fa-globe"></i> IRC Server</label> <label for="node-config-input-server"><i class="fa fa-globe"></i> <span data-i18n="irc.label.ircserver"></span></label>
<input type="text" id="node-config-input-server" placeholder="irc.freenode.net" style="width: 45%;" > <input type="text" id="node-config-input-server" placeholder="irc.freenode.net" style="width: 45%;" >
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label> <label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="irc.label.port"></span></label>
<input type="text" id="node-config-input-port" placeholder="Port" style="width:45px"> <input type="text" id="node-config-input-port" style="width:45px">
</div> </div>
<div class="form-row"> <div class="form-row">
<label>&nbsp;</label> <label>&nbsp;</label>
<input type="checkbox" id="node-config-input-ssl" style="display: inline-block; width: auto; vertical-align: top;"> <input type="checkbox" id="node-config-input-ssl" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-ssl" style="width: 70%;">Use Secure SSL connection ?</label> <label for="node-config-input-ssl" style="width: 70%;"><span data-i18n="irc.label.ssl"></span></label>
</div> </div>
<div class="form-row" id="certrow"> <div class="form-row" id="certrow">
<label>&nbsp;</label> <label>&nbsp;</label>
<input type="checkbox" id="node-config-input-cert" style="display: inline-block; width: auto; vertical-align: top;"> <input type="checkbox" id="node-config-input-cert" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-cert" style="width: 70%;">Allow self-signed certificates ?</label> <label for="node-config-input-cert" style="width: 70%;"><span data-i18n="irc.label.self"></span></label>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-config-input-nickname"><i class="fa fa-user"></i> Nickname</label> <label for="node-config-input-nickname"><i class="fa fa-user"></i> <span data-i18n="irc.label.nickname"></span></label>
<input type="text" id="node-config-input-nickname" placeholder="joe123"> <input type="text" id="node-config-input-nickname">
</div> </div>
</script> </script>

View File

@ -47,45 +47,45 @@ module.exports = function(RED) {
this.channel = n.channel || this.serverConfig.channel; this.channel = n.channel || this.serverConfig.channel;
var node = this; var node = this;
if (node.serverConfig.ircclient === null) { if (node.serverConfig.ircclient === null) {
node.log("CONNECT: "+node.serverConfig.server); node.log(RED._("irc.errors.connect")+": "+node.serverConfig.server);
node.status({fill:"grey",shape:"dot",text:"connecting"}); node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
var options = {autoConnect:true,autoRejoin:false,floodProtection:true,secure:node.serverConfig.ssl,selfSigned:node.serverConfig.cert,port:node.serverConfig.port,retryDelay:20000}; var options = {autoConnect:true,autoRejoin:false,floodProtection:true,secure:node.serverConfig.ssl,selfSigned:node.serverConfig.cert,port:node.serverConfig.port,retryDelay:20000};
node.serverConfig.ircclient = new irc.Client(node.serverConfig.server, node.serverConfig.nickname, options); node.serverConfig.ircclient = new irc.Client(node.serverConfig.server, node.serverConfig.nickname, options);
node.serverConfig.ircclient.setMaxListeners(0); node.serverConfig.ircclient.setMaxListeners(0);
node.serverConfig.ircclient.addListener('error', function(message) { node.serverConfig.ircclient.addListener('error', function(message) {
if (RED.settings.verbose) { node.log("ERR: "+JSON.stringify(message)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.err")+": "+JSON.stringify(message)); }
}); });
node.serverConfig.ircclient.addListener('netError', function(message) { node.serverConfig.ircclient.addListener('netError', function(message) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("NET: "+JSON.stringify(message)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.net")+": "+JSON.stringify(message)); }
node.status({fill:"red",shape:"ring",text:"net error"}); node.status({fill:"red",shape:"ring",text:"node-red:common.status.neterror"});
}); });
node.serverConfig.ircclient.addListener('connect', function() { node.serverConfig.ircclient.addListener('connect', function() {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("CONNECTED "); } if (RED.settings.verbose) { node.log(RED._("irc.errors.connected")); }
}); });
node.serverConfig.ircclient.addListener('registered', function(message) { node.serverConfig.ircclient.addListener('registered', function(message) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
node.log(node.serverConfig.ircclient.nick+" ONLINE: "+message.server); node.log(node.serverConfig.ircclient.nick+" "+RED._("irc.errors.online")+": "+message.server);
node.status({fill:"yellow",shape:"dot",text:"connected"}); node.status({fill:"yellow",shape:"dot",text:"node-red:common.status.connected"});
node.serverConfig.ircclient.join( node.channel, function(data) { node.serverConfig.ircclient.join( node.channel, function(data) {
node.log(data+" JOINED: "+node.channel); node.log(data+" "+RED._("irc.errors.joined")+": "+node.channel);
node.status({fill:"green",shape:"dot",text:"joined"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.joined"});
}); });
}); });
node.serverConfig.ircclient.addListener('ping', function(server) { node.serverConfig.ircclient.addListener('ping', function(server) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("PING from "+JSON.stringify(server)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.ping")+" "+JSON.stringify(server)); }
node.status({fill:"green",shape:"dot",text:"ok"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"});
}); });
node.serverConfig.ircclient.addListener('quit', function(nick, reason, channels, message) { node.serverConfig.ircclient.addListener('quit', function(nick, reason, channels, message) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("QUIT: "+nick+" "+reason+" "+channels+" "+JSON.stringify(message)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.quit")+": "+nick+" "+reason+" "+channels+" "+JSON.stringify(message)); }
node.status({fill:"grey",shape:"ring",text:"quit"}); node.status({fill:"grey",shape:"ring",text:"node-red:common.status.quit"});
//node.serverConfig.ircclient.disconnect( function() { //node.serverConfig.ircclient.disconnect( function() {
// node.serverConfig.ircclient.connect(); // node.serverConfig.ircclient.connect();
//}); //});
//if (RED.settings.verbose) { node.log("restart"); } // then retry //if (RED.settings.verbose) { node.log(RED._("irc.errors.restart")); } // then retry
}); });
node.serverConfig.ircclient.addListener('raw', function (message) { // any message received means we are alive node.serverConfig.ircclient.addListener('raw', function (message) { // any message received means we are alive
//console.log("RAW:"+JSON.stringify(message)); //console.log("RAW:"+JSON.stringify(message));
@ -102,8 +102,8 @@ module.exports = function(RED) {
if ((Date.now()-node.serverConfig.lastseen) > 300000) { // If more than 5 mins if ((Date.now()-node.serverConfig.lastseen) > 300000) { // If more than 5 mins
//node.serverConfig.ircclient.disconnect(); //node.serverConfig.ircclient.disconnect();
//node.serverConfig.ircclient.connect(); //node.serverConfig.ircclient.connect();
node.status({fill:"grey",shape:"ring",text:"no connection"}); node.status({fill:"grey",shape:"ring",text:"node-red:common.status.noconnection"});
if (RED.settings.verbose) { node.log("CONNECTION LOST ?"); } if (RED.settings.verbose) { node.log(RED._("irc.errors.connectionlost")); }
} }
//node.serverConfig.ircclient.send.apply(node.serverConfig.ircclient,["TIME"]); // request time to check link //node.serverConfig.ircclient.send.apply(node.serverConfig.ircclient,["TIME"]); // request time to check link
}, 60000); // check every 1 min }, 60000); // check every 1 min
@ -113,11 +113,11 @@ module.exports = function(RED) {
node.ircclient = node.serverConfig.ircclient; node.ircclient = node.serverConfig.ircclient;
node.ircclient.addListener('registered', function(message) { node.ircclient.addListener('registered', function(message) {
//node.log(node.ircclient.nick+" ONLINE"); //node.log(node.ircclient.nick+" "+RED._("irc.errors.online"));
node.status({fill:"yellow",shape:"dot",text:"connected"}); node.status({fill:"yellow",shape:"dot",text:"node-red:common.status.connected"});
node.ircclient.join( node.channel, function(data) { node.ircclient.join( node.channel, function(data) {
// node.log(data+" JOINED "+node.channel); // node.log(data+" "+RED._("irc.errors.joined")+" "+node.channel);
node.status({fill:"green",shape:"dot",text:"joined"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.joined"});
}); });
}); });
node.ircclient.addListener('message', function (from, to, message) { node.ircclient.addListener('message', function (from, to, message) {
@ -136,27 +136,27 @@ module.exports = function(RED) {
node.ircclient.addListener('join', function(channel, who) { node.ircclient.addListener('join', function(channel, who) {
var msg = { "payload": { "type":"join", "who":who, "channel":channel } }; var msg = { "payload": { "type":"join", "who":who, "channel":channel } };
node.send([null,msg]); node.send([null,msg]);
//node.log(who+' has joined '+channel); //node.log(who+' '+RED._("irc.errors.hasjoined")+' '+channel);
}); });
node.ircclient.addListener('invite', function(channel, from, message) { node.ircclient.addListener('invite', function(channel, from, message) {
var msg = { "payload": { "type":"invite", "who":from, "channel":channel, "message":message } }; var msg = { "payload": { "type":"invite", "who":from, "channel":channel, "message":message } };
node.send([null,msg]); node.send([null,msg]);
//node.log(from+' sent invite to '+channel+': '+message); //node.log(from+' '+RED._("irc.errors.sentinvite")+' '+channel+': '+message);
}); });
node.ircclient.addListener('part', function(channel, who, reason) { node.ircclient.addListener('part', function(channel, who, reason) {
var msg = { "payload": { "type":"part", "who":who, "channel":channel, "reason":reason } }; var msg = { "payload": { "type":"part", "who":who, "channel":channel, "reason":reason } };
node.send([null,msg]); node.send([null,msg]);
//node.log(who+' has left '+channel+': '+reason); //node.log(who+' '+RED._("irc.errors.hasleft")+' '+channel+': '+reason);
}); });
node.ircclient.addListener('quit', function(nick, reason, channels, message) { node.ircclient.addListener('quit', function(nick, reason, channels, message) {
var msg = { "payload": { "type":"quit", "who":nick, "channel":channels, "reason":reason } }; var msg = { "payload": { "type":"quit", "who":nick, "channel":channels, "reason":reason } };
node.send([null,msg]); node.send([null,msg]);
//node.log(nick+' has quit '+channels+': '+reason); //node.log(nick+' '+RED._("irc.errors.hasquit")+' '+channels+': '+reason);
}); });
node.ircclient.addListener('kick', function(channel, who, by, reason) { node.ircclient.addListener('kick', function(channel, who, by, reason) {
var msg = { "payload": { "type":"kick", "who":who, "channel":channel, "by":by, "reason":reason } }; var msg = { "payload": { "type":"kick", "who":who, "channel":channel, "by":by, "reason":reason } };
node.send([null,msg]); node.send([null,msg]);
//node.log(who+' was kicked from '+channel+' by '+by+': '+reason); //node.log(who+' '+RED._("irc.errors.kickedfrom")+' '+channel+' by '+by+': '+reason);
}); });
node.ircclient.addListener('names', function (channel, nicks) { node.ircclient.addListener('names', function (channel, nicks) {
var msg = { "payload": { "type": "names", "channel": channel, "names": nicks} }; var msg = { "payload": { "type": "names", "channel": channel, "names": nicks} };
@ -182,45 +182,45 @@ module.exports = function(RED) {
this.channel = n.channel || this.serverConfig.channel; this.channel = n.channel || this.serverConfig.channel;
var node = this; var node = this;
if (node.serverConfig.ircclient === null) { if (node.serverConfig.ircclient === null) {
node.log("CONNECT: "+node.serverConfig.server); node.log(RED._("irc.errors.connect")+": "+node.serverConfig.server);
node.status({fill:"grey",shape:"dot",text:"connecting"}); node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
var options = {autoConnect:true,autoRejoin:false,floodProtection:true,secure:node.serverConfig.ssl,selfSigned:node.serverConfig.cert,port:node.serverConfig.port,retryDelay:20000}; var options = {autoConnect:true,autoRejoin:false,floodProtection:true,secure:node.serverConfig.ssl,selfSigned:node.serverConfig.cert,port:node.serverConfig.port,retryDelay:20000};
node.serverConfig.ircclient = new irc.Client(node.serverConfig.server, node.serverConfig.nickname, options); node.serverConfig.ircclient = new irc.Client(node.serverConfig.server, node.serverConfig.nickname, options);
node.serverConfig.ircclient.setMaxListeners(0); node.serverConfig.ircclient.setMaxListeners(0);
node.serverConfig.ircclient.addListener('error', function(message) { node.serverConfig.ircclient.addListener('error', function(message) {
if (RED.settings.verbose) { node.log("ERR: "+JSON.stringify(message)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.err")+": "+JSON.stringify(message)); }
}); });
node.serverConfig.ircclient.addListener('netError', function(message) { node.serverConfig.ircclient.addListener('netError', function(message) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("NET: "+JSON.stringify(message)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.net")+": "+JSON.stringify(message)); }
node.status({fill:"red",shape:"ring",text:"net error"}); node.status({fill:"red",shape:"ring",text:"node-red:common.status.neterror"});
}); });
node.serverConfig.ircclient.addListener('connect', function() { node.serverConfig.ircclient.addListener('connect', function() {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("CONNECTED "); } if (RED.settings.verbose) { node.log(RED._("irc.errors.connected")); }
}); });
node.serverConfig.ircclient.addListener('registered', function(message) { node.serverConfig.ircclient.addListener('registered', function(message) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
node.log(node.serverConfig.ircclient.nick+" ONLINE: "+message.server); node.log(node.serverConfig.ircclient.nick+" "+RED._("irc.errors.online")+": "+message.server);
node.status({fill:"yellow",shape:"dot",text:"connected"}); node.status({fill:"yellow",shape:"dot",text:"node-red:common.status.connected"});
node.serverConfig.ircclient.join( node.channel, function(data) { node.serverConfig.ircclient.join( node.channel, function(data) {
node.log(data+" JOINED: "+node.channel); node.log(data+" "+RED._("irc.errors.joined")+": "+node.channel);
node.status({fill:"green",shape:"dot",text:"joined"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.joined"});
}); });
}); });
node.serverConfig.ircclient.addListener('ping', function(server) { node.serverConfig.ircclient.addListener('ping', function(server) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("PING from "+JSON.stringify(server)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.ping")+" "+JSON.stringify(server)); }
node.status({fill:"green",shape:"dot",text:"ok"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"});
}); });
node.serverConfig.ircclient.addListener('quit', function(nick, reason, channels, message) { node.serverConfig.ircclient.addListener('quit', function(nick, reason, channels, message) {
node.serverConfig.lastseen = Date.now(); node.serverConfig.lastseen = Date.now();
if (RED.settings.verbose) { node.log("QUIT: "+nick+" "+reason+" "+channels+" "+JSON.stringify(message)); } if (RED.settings.verbose) { node.log(RED._("irc.errors.quit")+": "+nick+" "+reason+" "+channels+" "+JSON.stringify(message)); }
node.status({fill:"grey",shape:"ring",text:"quit"}); node.status({fill:"grey",shape:"ring",text:"node-red:common.status.quit"});
//node.serverConfig.ircclient.disconnect( function() { //node.serverConfig.ircclient.disconnect( function() {
// node.serverConfig.ircclient.connect(); // node.serverConfig.ircclient.connect();
//}); //});
//if (RED.settings.verbose) { node.log("restart"); } // then retry //if (RED.settings.verbose) { node.log(RED._("irc.errors.restart")); } // then retry
}); });
node.serverConfig.ircclient.addListener('raw', function (message) { // any message received means we are alive node.serverConfig.ircclient.addListener('raw', function (message) { // any message received means we are alive
//console.log("RAW:"+JSON.stringify(message)); //console.log("RAW:"+JSON.stringify(message));
@ -237,8 +237,8 @@ module.exports = function(RED) {
if ((Date.now()-node.serverConfig.lastseen) > 300000) { // If more than 5 mins if ((Date.now()-node.serverConfig.lastseen) > 300000) { // If more than 5 mins
//node.serverConfig.ircclient.disconnect(); //node.serverConfig.ircclient.disconnect();
//node.serverConfig.ircclient.connect(); //node.serverConfig.ircclient.connect();
node.status({fill:"grey",shape:"ring",text:"no connection"}); node.status({fill:"grey",shape:"ring",text:"node-red:common.status.noconnection"});
if (RED.settings.verbose) { node.log("CONNECTION LOST ?"); } if (RED.settings.verbose) { node.log(RED._("irc.errors.connectionlost")); }
} }
//node.serverConfig.ircclient.send.apply(node.serverConfig.ircclient,["TIME"]); // request time to check link //node.serverConfig.ircclient.send.apply(node.serverConfig.ircclient,["TIME"]); // request time to check link
}, 60000); // check every 1 min }, 60000); // check every 1 min
@ -249,7 +249,7 @@ module.exports = function(RED) {
node.on("input", function(msg) { node.on("input", function(msg) {
if (Object.prototype.toString.call( msg.raw ) === '[object Array]') { if (Object.prototype.toString.call( msg.raw ) === '[object Array]') {
if (RED.settings.verbose) { node.log("RAW command:"+msg.raw); } if (RED.settings.verbose) { node.log(RED._("irc.errors.rawcommand")+":"+msg.raw); }
node.ircclient.send.apply(node.ircclient,msg.raw); node.ircclient.send.apply(node.ircclient,msg.raw);
} }
else { else {
@ -259,7 +259,7 @@ module.exports = function(RED) {
if ((msg.hasOwnProperty('topic'))&&(typeof msg.topic === "string")) { if ((msg.hasOwnProperty('topic'))&&(typeof msg.topic === "string")) {
ch = msg.topic.split(","); // split on , so we can send to multiple ch = msg.topic.split(","); // split on , so we can send to multiple
} }
else { node.warn("msg.topic not set"); } else { node.warn(RED._("irc.errors.topicnotset")); }
} }
for (var c = 0; c < ch.length; c++) { for (var c = 0; c < ch.length; c++) {
if (node.sendFlag == "false") { // send whole message object to each channel if (node.sendFlag == "false") { // send whole message object to each channel

View File

@ -0,0 +1,39 @@
{
"irc": {
"label": {
"ircserver": "IRC Server",
"channel": "Channel",
"action": "Action",
"port": "Port",
"ssl": "Use Secure SSL connection?",
"self": "Allow self-signed certificates?",
"nickname": "Nickname"
},
"payload": "Send payload to channel(s)",
"topic": "Use msg.topic to set nickname or channel(s)",
"msg": "Send complete msg object to channel(s)",
"tip": {
"in": "The channel to join must start with a #<br/>You may join multiple channels by comma separating a list - #chan1,#chan2,etc.",
"out": "The channel to join must start with a #<br/>Sending the complete object will stringify the whole msg object before sending."
},
"errors": {
"connect": "CONNECT",
"err": "ERR",
"net": "NET",
"connected": "CONNECTED",
"online": "ONLINE",
"joined": "JOINED",
"ping": "PING from",
"quit": "QUIT",
"restart": "restart",
"connectionlost": "CONNECTION LOST?",
"hasjoined": "has joined",
"sentinvite": "sent invite to",
"hasleft": "has left",
"hasquit": "has quit",
"kickedfrom": "was kicked from",
"rawcommand": "RAW command",
"topicnotset": "msg.topic not set"
}
}
}

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2013 IBM Corp. Copyright 2013, 2015 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -24,33 +24,6 @@
var twitterConfigNodeId = null; var twitterConfigNodeId = null;
var twitterConfigNodeIntervalId = null; var twitterConfigNodeIntervalId = null;
function showTwitterAuthStart() {
var pathname = document.location.pathname;
if (pathname.slice(-1) != "/") {
pathname += "/";
}
var callback = encodeURIComponent(location.protocol+"//"+location.hostname+":"+location.port+pathname+"twitter-credentials/"+twitterConfigNodeId+"/auth/callback");
$("#node-config-dialog-ok").button("disable");
$("#node-config-twitter-row").html('<div style="text-align: center; margin-top: 20px; "><a class="btn" id="node-config-twitter-start" href="twitter-credentials/'+twitterConfigNodeId+'/auth?callback='+callback+'" target="_blank">Click here to authenticate with Twitter.</a></div>');
$("#node-config-twitter-start").click(function() {
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
});
}
function updateTwitterScreenName(sn) {
$("#node-config-input-screen_name").val(sn);
$("#node-config-twitter-row").html('<label><i class="fa fa-user"></i> Twitter ID</label><span class="input-xlarge uneditable-input">'+sn+'</span>');
}
function pollTwitterCredentials(e) {
$.getJSON('credentials/twitter-credentials/'+twitterConfigNodeId,function(data) {
if (data.screen_name) {
updateTwitterScreenName(data.screen_name);
twitterConfigNodeIntervalId = null;
$("#node-config-dialog-ok").button("enable");
} else {
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
}
})
}
RED.nodes.registerType('twitter-credentials',{ RED.nodes.registerType('twitter-credentials',{
category: 'config', category: 'config',
defaults: { defaults: {
@ -66,7 +39,35 @@
}, },
exportable: false, exportable: false,
oneditprepare: function() { oneditprepare: function() {
twitterConfigNodeId = this.id; var clickhere = this._("twitter.label.clickhere");
var twitterID = this._("twitter.label.twitter-id");
function showTwitterAuthStart() {
var pathname = document.location.pathname;
if (pathname.slice(-1) != "/") {
pathname += "/";
}
var callback = encodeURIComponent(location.protocol+"//"+location.hostname+":"+location.port+pathname+"twitter-credentials/"+twitterConfigNodeId+"/auth/callback");
$("#node-config-dialog-ok").button("disable");
$("#node-config-twitter-row").html('<div style="text-align: center; margin-top: 20px; "><a class="btn" id="node-config-twitter-start" href="twitter-credentials/'+twitterConfigNodeId+'/auth?callback='+callback+'" target="_blank">'+clickhere+'</a></div>');
$("#node-config-twitter-start").click(function() {
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
});
}
function updateTwitterScreenName(sn) {
$("#node-config-input-screen_name").val(sn);
$("#node-config-twitter-row").html('<label><i class="fa fa-user"></i> '+twitterID+'</label><span class="input-xlarge uneditable-input">'+sn+'</span>');
}
function pollTwitterCredentials(e) {
$.getJSON('credentials/twitter-credentials/'+twitterConfigNodeId,function(data) {
if (data.screen_name) {
updateTwitterScreenName(data.screen_name);
twitterConfigNodeIntervalId = null;
$("#node-config-dialog-ok").button("enable");
} else {
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
}
})
}
if (!this.screen_name || this.screen_name === "") { if (!this.screen_name || this.screen_name === "") {
showTwitterAuthStart(); showTwitterAuthStart();
} else { } else {
@ -93,29 +94,27 @@
<script type="text/x-red" data-template-name="twitter in"> <script type="text/x-red" data-template-name="twitter in">
<div class="form-row"> <div class="form-row">
<label for="node-input-twitter"><i class="fa fa-user"></i> Log in as</label> <label for="node-input-twitter"><i class="fa fa-user"></i> <span data-i18n="twitter.label.twitter-id"></span></label>
<input type="text" id="node-input-twitter"> <input type="text" id="node-input-twitter">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-user"><i class="fa fa-search"></i> Search</label> <label for="node-input-user"><i class="fa fa-search"></i> <span data-i18n="twitter.label.search"></span></label>
<select type="text" id="node-input-user" style="display: inline-block; vertical-align: middle; width:60%;"> <select type="text" id="node-input-user" style="display: inline-block; vertical-align: middle; width:60%;">
<option value="false">all public tweets</option> <option value="false" data-i18n="twitter.search.public"></option>
<option value="true">the tweets of who you follow</option> <option value="true" data-i18n="twitter.search.follow"></option>
<option value="user">the tweets of specific users</option> <option value="user" data-i18n="twitter.search.user"></option>
<option value="dm">your direct messages</option> <option value="dm" data-i18n="twitter.search.direct"></option>
</select> </select>
</div> </div>
<div class="form-row" id="node-input-tags-row"> <div class="form-row" id="node-input-tags-row">
<label for="node-input-tags"><i class="fa fa-tags"></i> <span id="node-input-tags-label">for</span></label> <label for="node-input-tags"><i class="fa fa-tags"></i> <span id="node-input-tags-label" data-i18n="twitter.label.for"></span></label>
<input type="text" id="node-input-tags" placeholder="comma-separated words, @ids, #tags"> <input type="text" id="node-input-tags" data-i18n="[placeholder]twitter.placeholder.for">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
<div class="form-tips">Tip: Use commas without spaces between multiple search terms. Comma = OR, Space = AND. <div class="form-tips"><span data-i18n="[html]twitter.tip"></span></div>
<br/>The Twitter API WILL NOT deliver 100% of all tweets.
<br/>Tweets of who you follow will include their retweets and favourites.</div>
</script> </script>
<script type="text/x-red" data-help-name="twitter in"> <script type="text/x-red" data-help-name="twitter in">
@ -154,9 +153,9 @@
} }
if (this.user == "dm") { if (this.user == "dm") {
var user = RED.nodes.node(this.twitter); var user = RED.nodes.node(this.twitter);
return (user?user.label()+" ":"")+"DMs"; return (user?user.label()+" ":"")+this._("twitter.label.dmslabel");
} else if (this.user == "user") { } else if (this.user == "user") {
return this.tags+" tweets"; return this.tags+" "+this._("twitter.label.tweetslabel");
} }
return this.tags; return this.tags;
}, },
@ -164,18 +163,22 @@
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
}, },
oneditprepare: function() { oneditprepare: function() {
var userlabel = this._("twitter.label.user");
var userph = this._("twitter.placeholder.user");
var forlabel = this._("twitter.label.for");
var forph = this._("twitter.placeholder.for");
$("#node-input-user").change(function() { $("#node-input-user").change(function() {
var type = $("#node-input-user option:selected").val(); var type = $("#node-input-user option:selected").val();
if (type == "user") { if (type == "user") {
$("#node-input-tags-row").show(); $("#node-input-tags-row").show();
$("#node-input-tags-label").html("User"); $("#node-input-tags-label").html(userlabel);
$("#node-input-tags").attr("placeholder","comma-separated @twitter handles"); $("#node-input-tags").attr("placeholder",userph);
} else if (type == "dm") { } else if (type == "dm") {
$("#node-input-tags-row").hide(); $("#node-input-tags-row").hide();
} else { } else {
$("#node-input-tags-row").show(); $("#node-input-tags-row").show();
$("#node-input-tags-label").html("for"); $("#node-input-tags-label").html(forlabel);
$("#node-input-tags").attr("placeholder","comma-separated words, @ids, #hashtags"); $("#node-input-tags").attr("placeholder",forph);
} }
}); });
@ -187,12 +190,12 @@
<script type="text/x-red" data-template-name="twitter out"> <script type="text/x-red" data-template-name="twitter out">
<div class="form-row"> <div class="form-row">
<label for="node-input-twitter"><i class="fa fa-user"></i> Twitter</label> <label for="node-input-twitter"><i class="fa fa-user"></i> <span data-i18n="twitter.label.twitter-id"></span></label>
<input type="text" id="node-input-twitter"> <input type="text" id="node-input-twitter">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
</script> </script>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2013 IBM Corp. * Copyright 2013, 2015 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -191,9 +191,7 @@ module.exports = function(RED) {
if (bits.length == 4) { if (bits.length == 4) {
if ((Number(bits[0]) < Number(bits[2])) && (Number(bits[1]) < Number(bits[3]))) { if ((Number(bits[0]) < Number(bits[2])) && (Number(bits[1]) < Number(bits[3]))) {
st = { locations: node.tags }; st = { locations: node.tags };
} node.log(RED._("twitter.status.using-geo",{location:node.tags.toString()}));
else {
node.log("possible bad geo area format. Should be lower-left lon, lat, upper-right lon, lat");
} }
} }
@ -218,19 +216,19 @@ module.exports = function(RED) {
} }
}); });
stream.on('limit', function(tweet) { stream.on('limit', function(tweet) {
node.warn("tweet rate limit hit"); node.warn(RED._("twitter.errors.ratelimit"));
}); });
stream.on('error', function(tweet,rc) { stream.on('error', function(tweet,rc) {
if (rc == 420) { if (rc == 420) {
node.warn("Twitter rate limit hit"); node.warn(RED._("twitter.errors.ratelimit"));
} else { } else {
node.warn("Stream error:"+tweet.toString()+" ("+rc+")"); node.warn(RED._("twitter.errors.streamerror",{error:tweet.toString(),rc:rc}));
} }
setTimeout(setupStream,10000); setTimeout(setupStream,10000);
}); });
stream.on('destroy', function (response) { stream.on('destroy', function (response) {
if (this.active) { if (this.active) {
node.warn("twitter ended unexpectedly"); node.warn(RED._("twitter.errors.unexpectedend"));
setTimeout(setupStream,10000); setTimeout(setupStream,10000);
} }
}); });
@ -243,10 +241,10 @@ module.exports = function(RED) {
node.error(err); node.error(err);
} }
} else { } else {
this.error("Invalid tag property"); this.error(RED._("twitter.errors.invalidtag"));
} }
} else { } else {
this.error("missing twitter credentials"); this.error(RED._("twitter.errors.missingcredentials"));
} }
this.on('close', function() { this.on('close', function() {
@ -281,11 +279,11 @@ module.exports = function(RED) {
}); });
node.on("input", function(msg) { node.on("input", function(msg) {
if (msg.hasOwnProperty("payload")) { if (msg.hasOwnProperty("payload")) {
node.status({fill:"blue",shape:"dot",text:"tweeting"}); node.status({fill:"blue",shape:"dot",text:"twitter.status.tweeting"});
if (msg.payload.length > 140) { if (msg.payload.length > 140) {
msg.payload = msg.payload.slice(0,139); msg.payload = msg.payload.slice(0,139);
node.warn("Tweet greater than 140 : truncated"); node.warn(RED._("twitter.errors.truncated"));
} }
if (msg.media && Buffer.isBuffer(msg.media)) { if (msg.media && Buffer.isBuffer(msg.media)) {
@ -298,13 +296,13 @@ module.exports = function(RED) {
var r = request.post(signedUrl,function(err,httpResponse,body) { var r = request.post(signedUrl,function(err,httpResponse,body) {
if (err) { if (err) {
node.error(err,msg); node.error(err,msg);
node.status({fill:"red",shape:"ring",text:"failed"}); node.status({fill:"red",shape:"ring",text:"twitter.status.failed"});
} else { } else {
var response = JSON.parse(body); var response = JSON.parse(body);
if (response.errors) { if (response.errors) {
var errorList = response.errors.map(function(er) { return er.code+": "+er.message }).join(", "); var errorList = response.errors.map(function(er) { return er.code+": "+er.message }).join(", ");
node.error("Send tweet failed: "+errorList,msg); node.error(RED._("twitter.errors.sendfail",{error:errorList}),msg);
node.status({fill:"red",shape:"ring",text:"failed"}); node.status({fill:"red",shape:"ring",text:"twitter.status.failed"});
} else { } else {
node.status({}); node.status({});
} }
@ -317,14 +315,14 @@ module.exports = function(RED) {
} else { } else {
twit.updateStatus(msg.payload, function (err, data) { twit.updateStatus(msg.payload, function (err, data) {
if (err) { if (err) {
node.status({fill:"red",shape:"ring",text:"failed"}); node.status({fill:"red",shape:"ring",text:"twitter.status.failed"});
node.error(err,msg); node.error(err,msg);
} }
node.status({}); node.status({});
}); });
} }
} }
else { node.warn("No payload to tweet"); } else { node.warn(RED._("twitter.errors.nopayload")); }
}); });
} }
} }
@ -346,10 +344,8 @@ module.exports = function(RED) {
oauth_callback: req.query.callback oauth_callback: req.query.callback
},function(error, oauth_token, oauth_token_secret, results) { },function(error, oauth_token, oauth_token_secret, results) {
if (error) { if (error) {
var resp = '<h2>Oh no!</h2>'+ var err = {statusCode: 401, data: "dummy error"};
'<p>Something went wrong with the authentication process. The following error was returned:<p>'+ var resp = RED._("twitter.errors.oautherror",{statusCode: err.statusCode, errorData: err.data});
'<p><b>'+error.statusCode+'</b>: '+error.data+'</p>'+
'<p>One known cause of this type of failure is if the clock is wrong on system running Node-RED.';
res.send(resp) res.send(resp)
} else { } else {
credentials.oauth_token = oauth_token; credentials.oauth_token = oauth_token;
@ -371,14 +367,14 @@ module.exports = function(RED) {
function(error, oauth_access_token, oauth_access_token_secret, results) { function(error, oauth_access_token, oauth_access_token_secret, results) {
if (error) { if (error) {
RED.log.error(error); RED.log.error(error);
res.send("something in twitter oauth broke."); res.send(RED._("twitter.errors.oauthbroke"));
} else { } else {
credentials = {}; credentials = {};
credentials.access_token = oauth_access_token; credentials.access_token = oauth_access_token;
credentials.access_token_secret = oauth_access_token_secret; credentials.access_token_secret = oauth_access_token_secret;
credentials.screen_name = "@"+results.screen_name; credentials.screen_name = "@"+results.screen_name;
RED.nodes.addCredentials(req.params.id,credentials); RED.nodes.addCredentials(req.params.id,credentials);
res.send("<html><head></head><body>Authorised - you can close this window and return to Node-RED</body></html>"); res.send(RED._("twitter.errors.authorized"));
} }
} }
); );

View File

@ -0,0 +1,43 @@
{
"twitter": {
"label": {
"twitter-id":"Twitter ID",
"search": "Search",
"for": "for",
"user": "User",
"dmslabel": "DMs",
"tweetslabel": "tweets",
"clickhere": "Click here to authenticate with Twitter."
},
"placeholder": {
"for": "comma-separated words, @ids, #tags",
"user": "comma-separated @twitter handles"
},
"search": {
"public": "all public tweets",
"follow": "the tweets of who you follow",
"user": "the tweets of specific users",
"direct": "your direct messages"
},
"tip": "Tip: Use commas without spaces between multiple search terms. Comma = OR, Space = AND.<br/>The Twitter API WILL NOT deliver 100% of all tweets.<br/>Tweets of who you follow will include their retweets and favourites.",
"status": {
"using-geo": "Using geo location: __location__",
"tweeting": "tweeting",
"failed":"failed"
},
"errors": {
"ratelimit":"tweet rate limit hit",
"streamerror":"stream error: __error__ (__rc__)",
"unexpectedend":"stream ended unexpectedly",
"invalidtag":"invalid tag property",
"missingcredentials":"missing twitter credentials",
"truncated":"truncated tweet greater than 140 characters",
"sendfail":"send tweet failed: __error__",
"nopayload":"no payload to tweet",
"oauthbroke":"something in twitter oauth broke.",
"oautherror": "<html><head></head><body><p>Something went wrong with the authentication process. The following error was returned:</p><p><b>__statusCode__</b>: __errorData__</p><p>One known cause of this type of failure is if the clock is wrong on system running Node-RED</p></body></html>",
"authorized": "<html><head></head><body><p>Authorised - you can close this window and return to Node-RED</p></body></html>"
}
}
}

View File

@ -1,6 +1,6 @@
{ {
"name" : "node-red-node-twitter", "name" : "node-red-node-twitter",
"version" : "0.0.6", "version" : "0.1.0",
"description" : "A Node-RED node to talk to Twitter", "description" : "A Node-RED node to talk to Twitter",
"dependencies" : { "dependencies" : {
"twitter-ng": "0.6.2", "twitter-ng": "0.6.2",

View File

@ -16,26 +16,26 @@
<script type="text/x-red" data-template-name="mongodb"> <script type="text/x-red" data-template-name="mongodb">
<div class="form-row"> <div class="form-row">
<label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> Host</label> <label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> <span data-i18n="mongodb.label.host"></span></label>
<input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" > <input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" >
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label> <label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="mongodb.label.port"></span></label>
<input type="text" id="node-config-input-port" placeholder="27017" style="width:45px"> <input type="text" id="node-config-input-port" style="width:45px">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-config-input-db"><i class="fa fa-database"></i> Database</label> <label for="node-config-input-db"><i class="fa fa-database"></i> <span data-i18n="mongodb.label.database"></span></label>
<input type="text" id="node-config-input-db" placeholder="test"> <input type="text" id="node-config-input-db">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-config-input-user"><i class="fa fa-user"></i> Username</label> <label for="node-config-input-user"><i class="fa fa-user"></i> <span data-i18n="mongodb.label.username"></span></label>
<input type="text" id="node-config-input-user"> <input type="text" id="node-config-input-user">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label> <label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="mongodb.label.password"></span></label>
<input type="password" id="node-config-input-password"> <input type="password" id="node-config-input-password">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-config-input-name" placeholder="Name"> <input type="text" id="node-config-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div> </div>
</script> </script>
@ -62,43 +62,42 @@
<script type="text/x-red" data-template-name="mongodb out"> <script type="text/x-red" data-template-name="mongodb out">
<div class="form-row"> <div class="form-row">
<label for="node-input-mongodb"><i class="fa fa-bookmark"></i> Server</label> <label for="node-input-mongodb"><i class="fa fa-bookmark"></i> <span data-i18n="mongodb.label.server"></span></label>
<input type="text" id="node-input-mongodb"> <input type="text" id="node-input-mongodb">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-collection"><i class="fa fa-briefcase"></i> Collection</label> <label for="node-input-collection"><i class="fa fa-briefcase"></i> <span data-i18n="mongodb.label.collection"></span></label>
<input type="text" id="node-input-collection" placeholder="collection"> <input type="text" id="node-input-collection">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label> <label for="node-input-operation"><i class="fa fa-wrench"></i> <span data-i18n="mongodb.label.operation"></span></label>
<select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;"> <select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;">
<option value="store">save</option> <option value="store" data-i18n="mongodb.operation.save"></option>
<option value="insert">insert</option> <option value="insert" data-i18n="mongodb.operation.insert"></option>
<option value="update">update</option> <option value="update" data-i18n="mongodb.operation.update"></option>
<option value="delete">remove</option> <option value="delete" data-i18n="mongodb.operation.remove"></option>
</select> </select>
</div> </div>
<div class="form-row node-input-payonly"> <div class="form-row node-input-payonly">
<label>&nbsp;</label> <label>&nbsp;</label>
<input type="checkbox" id="node-input-payonly" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;"> <input type="checkbox" id="node-input-payonly" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-payonly" style="width: 70%;">Only store msg.payload object</label> <label for="node-input-payonly" style="width: 70%;"><span data-i18n="mongodb.label.onlystore"></span></label>
</div> </div>
<div class="form-row node-input-upsert"> <div class="form-row node-input-upsert">
<label>&nbsp;</label> <label>&nbsp;</label>
<input type="checkbox" id="node-input-upsert" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;"> <input type="checkbox" id="node-input-upsert" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-upsert" style="width: 70%;">Create a new document if no match found</label> <label for="node-input-upsert" style="width: 70%;"><span data-i18n="mongodb.label.createnew"></span></label>
</div> </div>
<div class="form-row node-input-multi"> <div class="form-row node-input-multi">
<label>&nbsp;</label> <label>&nbsp;</label>
<input type="checkbox" id="node-input-multi" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;;"> <input type="checkbox" id="node-input-multi" style="display: inline-block; width: auto; vertical-align: top;;">
<label for="node-input-multi" style="width: 70%;">Update all matching documents</label> <label for="node-input-multi" style="width: 70%;"><span data-i18n="mongodb.label.updateall"></span></label>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-tips" id="node-warning" style="display: none"><b> Tip:</b> If no collection is set, ensure <b>msg.collection</b> will contain the collection name
</div> </div>
<div class="form-tips" id="node-warning" style="display: none"><span data-i18n="[html]mongodb.tip"></span></div>
</script> </script>
<script type="text/x-red" data-help-name="mongodb out"> <script type="text/x-red" data-help-name="mongodb out">
@ -172,27 +171,26 @@
<script type="text/x-red" data-template-name="mongodb in"> <script type="text/x-red" data-template-name="mongodb in">
<div class="form-row"> <div class="form-row">
<label for="node-input-mongodb"><i class="fa fa-bookmark"></i> Server</label> <label for="node-input-mongodb"><i class="fa fa-bookmark"></i> <span data-i18n="mongodb.label.server"></span></label>
<input type="text" id="node-input-mongodb"> <input type="text" id="node-input-mongodb">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-collection"><i class="fa fa-briefcase"></i> Collection</label> <label for="node-input-collection"><i class="fa fa-briefcase"></i> <span data-i18n="mongodb.label.collection"></span></label>
<input type="text" id="node-input-collection" placeholder="collection"> <input type="text" id="node-input-collection">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label> <label for="node-input-operation"><i class="fa fa-wrench"></i> <span data-i18n="mongodb.label.operation"></span></label>
<select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;"> <select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;">
<option value="find">find</option> <option value="find" data-i18n="mongodb.operation.find"></option>
<option value="count">count</option> <option value="count" data-i18n="mongodb.operation.count"></option>
<option value="aggregate">aggregate</option> <option value="aggregate" data-i18n="mongodb.operation.aggregate"></option>
</select> </select>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-tips" id="node-warning" style="display: none"><b> Tip:</b> If no collection is set, ensure <b>msg.collection</b> will contain the collection name
</div> </div>
<div class="form-tips" id="node-warning" style="display: none"><span data-i18n="[html]mongodb.tip"></span></div>
</script> </script>
<script type="text/x-red" data-help-name="mongodb in"> <script type="text/x-red" data-help-name="mongodb in">

View File

@ -76,7 +76,7 @@ module.exports = function(RED) {
if (msg.collection) { if (msg.collection) {
coll = db.collection(msg.collection); coll = db.collection(msg.collection);
} else { } else {
node.error("No collection defined",msg); node.error(RED._("mongodb.errors.nocollection"),msg);
return; return;
} }
} }
@ -149,7 +149,7 @@ module.exports = function(RED) {
} }
}); });
} else { } else {
this.error("missing mongodb configuration"); this.error(RED._("mongodb.errors.missingconfig"));
} }
this.on("close", function() { this.on("close", function() {
@ -183,7 +183,7 @@ module.exports = function(RED) {
if (msg.collection) { if (msg.collection) {
coll = db.collection(msg.collection); coll = db.collection(msg.collection);
} else { } else {
node.error("No collection defined"); node.error(RED._("mongodb.errors.nocollection"));
return; return;
} }
} }
@ -237,7 +237,7 @@ module.exports = function(RED) {
} }
}); });
} else { } else {
this.error("missing mongodb configuration"); this.error(RED._("mongodb.errors.missingconfig"));
} }
this.on("close", function() { this.on("close", function() {

View File

@ -0,0 +1,31 @@
{
"mongodb": {
"label": {
"host": "Host",
"port": "Port",
"database": "Database",
"username": "Username",
"password": "Password",
"server": "Server",
"collection": "Collection",
"operation": "Operation",
"onlystore": "Only store msg.payload object",
"createnew": "Create a new document if no match found",
"updateall": "Update all matching documents"
},
"operation": {
"save": "save",
"insert": "insert",
"update": "update",
"remove": "remove",
"find": "find",
"count": "count",
"aggregate": "aggregate"
},
"tip": "<b> Tip:</b> If no collection is set, ensure <b>msg.collection</b> will contain the collection name",
"errors": {
"nocollection": "No collection defined",
"missingconfig": "missing mongodb configuration"
}
}
}

View File

@ -16,32 +16,29 @@
<script type="text/x-red" data-template-name="redis out"> <script type="text/x-red" data-template-name="redis out">
<div class="form-row node-input-hostname"> <div class="form-row node-input-hostname">
<label for="node-input-hostname"><i class="fa fa-bookmark"></i> Host</label> <label for="node-input-hostname"><i class="fa fa-bookmark"></i> <span data-i18n="redisout.label.host"></span></label>
<input class="input-append-left" type="text" id="node-input-hostname" placeholder="127.0.0.1" style="width: 40%;" ><button id="node-input-hostname-lookup" class="btn input-append-right"><span class="caret"></span></button> <input class="input-append-left" type="text" id="node-input-hostname" placeholder="127.0.0.1" style="width: 40%;" ><button id="node-input-hostname-lookup" class="btn input-append-right"><span class="caret"></span></button>
<label for="node-input-port" style="margin-left: 10px; width: 35px; "> Port</label> <label for="node-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="redisout.label.port"></span></label>
<input type="text" id="node-input-port" placeholder="6379" style="width:45px"> <input type="text" id="node-input-port" placeholder="6379" style="width:45px">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-key"><i class="fa fa-key"></i> Key</label> <label for="node-input-key"><i class="fa fa-key"></i> <span data-i18n="redisout.label.key"></span></label>
<input type="text" id="node-input-key" placeholder="Redis Key"> <input type="text" id="node-input-key">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-type"><i class="fa fa-th"></i> Type</label> <label for="node-input-type"><i class="fa fa-th"></i> <span data-i18n="redisout.label.type"></span></label>
<select type="text" id="node-input-structtype" style="width: 150px;"> <select type="text" id="node-input-structtype" style="width: 150px;">
<option value="string">String</option> <option value="string" data-i18n="redisout.type.string"></option>
<option value="hash">Hash</option> <option value="hash" data-i18n="redisout.type.hash"></option>
<option value="set">Set</option> <option value="set" data-i18n="redisout.type.set"></option>
<option value="list">List</option> <option value="list" data-i18n="redisout.type.list"></option>
</select> </select>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-tips">
If key is blank, the topic will be used as the key.<br>
If type is hash, payload should be an object or field=value string.
</div> </div>
<div class="form-tips"><span data-i18n="[html]redisout.tip"></span></div>
</script> </script>
<script type="text/x-red" data-help-name="redis out"> <script type="text/x-red" data-help-name="redis out">

View File

@ -30,9 +30,6 @@ module.exports = function(RED) {
connections[id].on("error",function(err) { connections[id].on("error",function(err) {
RED.log.error(err); RED.log.error(err);
}); });
connections[id].on("connect",function() {
if (RED.settings.verbose) { RED.log.info("connected to "+host+":"+port); }
});
connections[id]._id = id; connections[id]._id = id;
connections[id]._nodeCount = 0; connections[id]._nodeCount = 0;
} }
@ -64,17 +61,17 @@ module.exports = function(RED) {
this.client = redisConnectionPool.get(this.hostname,this.port); this.client = redisConnectionPool.get(this.hostname,this.port);
if (this.client.connected) { if (this.client.connected) {
this.status({fill:"green",shape:"dot",text:"connected"}); this.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
} else { } else {
this.status({fill:"red",shape:"ring",text:"disconnected"},true); this.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"},true);
} }
var node = this; var node = this;
this.client.on("end", function() { this.client.on("end", function() {
node.status({fill:"red",shape:"ring",text:"disconnected"}); node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
}); });
this.client.on("connect", function() { this.client.on("connect", function() {
node.status({fill:"green",shape:"dot",text:"connected"}); node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
}); });
this.on("input", function(msg) { this.on("input", function(msg) {
@ -90,7 +87,7 @@ module.exports = function(RED) {
if (r) { if (r) {
this.client.hset(k,r[1],r[2]); this.client.hset(k,r[1],r[2]);
} else { } else {
this.warn("Invalid payload for redis hash"); this.warn(RED._("redisout.errors.invalidpayload"));
} }
} }
} else if (this.structtype == "set") { } else if (this.structtype == "set") {
@ -99,7 +96,7 @@ module.exports = function(RED) {
this.client.rpush(k,msg.payload); this.client.rpush(k,msg.payload);
} }
} else { } else {
this.warn("No key or topic set"); this.warn(RED._("redisout.errors.nokey"));
} }
}); });
this.on("close", function() { this.on("close", function() {

View File

@ -0,0 +1,21 @@
{
"redisout": {
"label": {
"host": "Host",
"port": "Port",
"key": "Key",
"type": "Type"
},
"type": {
"string": "String",
"hash": "Hash",
"set": "Set",
"list": "List"
},
"tip": "If key is blank, the topic will be used as the key.<br>If type is hash, payload should be an object or field=value string.",
"errors": {
"invalidpayload": "Invalid payload for redis hash",
"nokey": "No key or topic set"
}
}
}

View File

@ -150,7 +150,7 @@ describe('rbe node', function() {
msg.should.have.property('level', helper.log().WARN); msg.should.have.property('level', helper.log().WARN);
msg.should.have.property('id', 'n1'); msg.should.have.property('id', 'n1');
msg.should.have.property('type', 'rbe'); msg.should.have.property('type', 'rbe');
msg.should.have.property('msg', 'no number found in payload'); msg.should.have.property('msg', 'rbe.warn.nonumber');
done(); done();
},50); },50);
n1.emit("input", {payload:"banana"}); n1.emit("input", {payload:"banana"});

View File

@ -103,5 +103,4 @@ describe('email Node', function() {
}) })
}); });
}); });