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

Merge pull request #2 from node-red/master

Re-sync
This commit is contained in:
Max Hadley 2014-04-15 20:55:06 +01:00
commit de655a6dde
17 changed files with 697 additions and 169 deletions

View File

@ -16,13 +16,7 @@
// Require main module // Require main module
var RED = require(process.env.NODE_RED_HOME + "/red/red"); var RED = require(process.env.NODE_RED_HOME + "/red/red");
// Require bonescript
try {
var bonescript = require("bonescript"); var bonescript = require("bonescript");
} catch (err) {
require("util").log("[145-BBB-hardware] Error: cannot find module 'bonescript'");
}
// Node constructor for bbb-analogue-in // Node constructor for bbb-analogue-in
function AnalogueInputNode(n) { function AnalogueInputNode(n) {

View File

@ -52,10 +52,11 @@
</script> </script>
<script type="text/x-red" data-help-name="rpi-piface in"> <script type="text/x-red" data-help-name="rpi-piface in">
<p>Raspberry Pi PiFace input node. Generates a <b>msg.payload</b> with either a 0 or 1 depending on the state of the input pin. Requires the gpio command to work.</p> <p>Raspberry Pi PiFace input node. Generates a <b>msg.payload</b> with either a 0 or 1 depending on the state of the input pin.</p>
<p>You may also enable the input pullup resitor if required.</p> <p>You may also enable the input pullup resistor if required.</p>
<p>The <b>msg.topic</b> is set to <i>pi/{the pin number}</i></p> <p>The <b>msg.topic</b> is set to <i>piface/{the pin number}</i></p>
<p><b>Note:</b> This node currently polls the pin every 250mS. This is not ideal as it loads the cpu, and will be rewritten shortly to try to use interrupts.</p> <p>Requires the WiringPi gpio command in order to work.</p>
<p><b>Note:</b> This node currently polls the pin every 250mS. This is not ideal as it loads the cpu.</p>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
@ -103,9 +104,9 @@
</script> </script>
<script type="text/x-red" data-help-name="rpi-piface out"> <script type="text/x-red" data-help-name="rpi-piface out">
<p>Raspberry Pi PiFace output node. The PiFace board must be fitted. Requires the gpio command to work.</p> <p>Raspberry Pi PiFace output node. The PiFace board must be fitted.</p>
<p>Expects a <b>msg.payload</b> with either a 0 or 1 (or true or false).</p> <p>Will set the selected relay, LED, or pin on or off depending on the value passed in. Expects a <b>msg.payload</b> with either a 1 or 0 (or true or false).</p>
<p>Will set the selected relay, LED, or pin on or off depending on the value passed in.</p> <p>Requires the WiringPi gpio command in order to work.</p>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">

View File

@ -57,6 +57,33 @@ var pintable = {
"LED 6":"206", "LED 6":"206",
"LED 7":"207" "LED 7":"207"
} }
var tablepin = {
// WiringPi : Physical
"200":"S1",
"201":"S2",
"202":"S3",
"203":"S4",
"204":"I5",
"205":"I6",
"206":"I7",
"207":"I8",
"208":"O0",
"209":"O1",
"210":"O2",
"211":"O3",
"212":"O4",
"213":"O5",
"214":"O6",
"215":"O7",
"200":"L0",
"201":"L1",
"202":"L2",
"203":"L3",
"204":"L4",
"205":"L5",
"206":"L6",
"207":"L7"
}
function PiFACEInNode(n) { function PiFACEInNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
@ -76,7 +103,7 @@ function PiFACEInNode(n) {
var previousState = node.buttonState; var previousState = node.buttonState;
node.buttonState = Number(stdout); node.buttonState = Number(stdout);
if (previousState !== -1) { if (previousState !== -1) {
var msg = {topic:"pi/"+node.pin, payload:node.buttonState}; var msg = {topic:"piface/"+tablepin[node.pin], payload:node.buttonState};
node.send(msg); node.send(msg);
} }
} }

View File

@ -0,0 +1,111 @@
<!--
Copyright 2014 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-template-name="rpi-pibrella in">
<div class="form-row">
<label for="node-input-pin"><i class="icon-asterisk"></i> Input</label>
<select type="text" id="node-input-pin" style="width: 150px;">
<option value="-">select input</option>
<option value="Red Button">Red Button</option>
<option value="In A">In A</option>
<option value="In B">In B</option>
<option value="In C">In C</option>
<option value="In D">In D</option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="rpi-pibrella in">
<p>Raspberry Pi Pibrella input node. Generates a <b>msg.payload</b> with either a 0 or 1 depending on the state of the input pin.</p>
<p>The <b>msg.topic</b> is set to <i>pibrella/{the pin id}</i>, A, B, C, D or R</p>
<p><b>Note:</b> This node currently polls the pin every 250mS. This is not ideal as it loads the cpu.</p>
<p>Requires the WiringPi gpio command in order to work.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('rpi-pibrella in',{
category: 'advanced-input',
color:"#c6dbef",
defaults: {
name: { value:"" },
pin: { value:"",required:true,validate:RED.validators.regex(/ /) }
},
inputs:0,
outputs:1,
icon: "rpi.png",
label: function() {
return this.name||this.pin||"Pibrella";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="rpi-pibrella out">
<div class="form-row">
<label for="node-input-pin"><i class="icon-asterisk"></i> Output</label>
<select type="text" id="node-input-pin" style="width: 150px;">
<option value="-">select output</option>
<option value="Red LED">Red LED</option>
<option value="Amber LED">Amber LED</option>
<option value="Green LED">Green LED</option>
<option value="Out E">Out E</option>
<option value="Out F">Out F</option>
<option value="Out G">Out G</option>
<option value="Out H">Out H</option>
<option value="Buzzer ">Buzzer</option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips">Buzzer takes <b>msg.payload</b> between 2 (high) and 512 (low), or 0 for off.</div>
</script>
<script type="text/x-red" data-help-name="rpi-pibrella out">
<p>Raspberry Pi Pibrella output node. The Pibrella board must be fitted.</p>
<p>Will set the selected output high (on) or low (off) depending on the value passed in. Expects a <b>msg.payload</b> with either a 0 or 1 (or true or false).</p>
<p>The Buzzer is a divider so low numbers are high notes. 0 is off, and the sensible lowest note is around 250-300. 2 is the highest note. 1 is just a buzz (so you can use 0/1 type inputs).</p>
<p>Requires the WiringPi gpio command in order to work.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('rpi-pibrella out',{
category: 'advanced-output',
color:"#c6dbef",
defaults: {
name: { value:"" },
pin: { value:"",required:true,validate:RED.validators.regex(/ /) }
},
inputs:1,
outputs:0,
icon: "rpi.png",
align: "right",
label: function() {
return this.name||this.pin||"Pibrella";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>

View File

@ -0,0 +1,172 @@
/**
* Copyright 2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var RED = require(process.env.NODE_RED_HOME+"/red/red");
var util = require("util");
var exec = require('child_process').exec;
var fs = require('fs');
if (!fs.existsSync("/dev/ttyAMA0")) { // unlikely if not on a Pi
throw "Info : Ignoring Raspberry Pi specific node.";
}
if (!fs.existsSync("/usr/local/bin/gpio")) { // gpio command not installed
throw "Info : Can't find Raspberry Pi wiringPi gpio command.";
}
// Map physical P1 pins to Gordon's Wiring-Pi Pins (as they should be V1/V2 tolerant)
var pintable = {
// Physical : WiringPi
"Amber LED":"0",
"Buzzer ":"1",
"Red LED":"2",
"Out E":"3",
"Out F":"4",
"Out G":"5",
"Out H":"6",
"Green LED":"7",
"In C":"10",
"In B":"11",
"In D":"12",
"In A":"13",
"Red Button":"14",
}
var tablepin = {
// WiringPi : Physical
"0":"Amber",
"1":"Buzzer",
"2":"Red",
"3":"E",
"4":"F",
"5":"G",
"6":"H",
"7":"Green",
"10":"C",
"11":"B",
"12":"D",
"13":"A",
"14":"R",
}
function PibrellaIn(n) {
RED.nodes.createNode(this,n);
this.buttonState = -1;
this.pin = pintable[n.pin];
var node = this;
if (this.pin) {
exec("gpio mode "+node.pin+" in", function(err,stdout,stderr) {
if (err) node.error(err);
else {
node._interval = setInterval( function() {
exec("gpio read "+node.pin, function(err,stdout,stderr) {
if (err) node.error(err);
else {
if (node.buttonState !== Number(stdout)) {
var previousState = node.buttonState;
node.buttonState = Number(stdout);
if (previousState !== -1) {
var msg = {topic:"pibrella/"+tablepin[node.pin], payload:node.buttonState};
node.send(msg);
}
}
}
});
}, 200);
}
});
}
else {
this.error("Invalid GPIO pin: "+this.pin);
}
this.on("close", function() {
clearInterval(this._interval);
});
}
function PibrellaOut(n) {
RED.nodes.createNode(this,n);
this.pin = pintable[n.pin];
var node = this;
if (this.pin == "1") {
exec("gpio mode 1 pwm");
process.nextTick(function() {
exec("gpio pwm-ms");
node.on("input", function(msg) {
var out = Number(msg.payload);
if (out == 1) { // fixed buzz
exec("gpio pwm 1 511");
exec("gpio pwmc 100");
}
else if ((out >= 2) && (out <= 9999)) { // set buzz to a value
exec("gpio pwm 1 511");
exec("gpio pwmc "+out);
}
else { exec("gpio pwm 1 0"); } // turn it off
});
});
}
else if (this.pin) {
process.nextTick(function() {
exec("gpio mode "+node.pin+" out", function(err,stdout,stderr) {
if (err) node.error(err);
else {
node.on("input", function(msg) {
if (msg.payload === "true") msg.payload = true;
if (msg.payload === "false") msg.payload = false;
var out = Number(msg.payload);
if ((out == 0)|(out == 1)) {
exec("gpio write "+node.pin+" "+out, function(err,stdout,stderr) {
if (err) node.error(err);
});
}
else node.warn("Invalid input - not 0 or 1");
});
}
});
});
}
else {
this.error("Invalid GPIO pin: "+this.pin);
}
this.on("close", function() {
exec("gpio mode "+this.pin+" in");
});
}
exec("gpio mode 0 out",function(err,stdout,stderr) {
if (err) {
util.log('[36-rpi-gpio.js] Error: "gpio" command failed for some reason.');
}
exec("gpio mode 1 out");
exec("gpio mode 2 out");
exec("gpio mode 3 out");
exec("gpio mode 4 out");
exec("gpio mode 5 out");
exec("gpio mode 6 out");
exec("gpio mode 7 out");
exec("gpio mode 10 in");
exec("gpio mode 11 in");
exec("gpio mode 12 in");
exec("gpio mode 13 in");
exec("gpio mode 14 in");
});
RED.nodes.registerType("rpi-pibrella in",PibrellaIn);
RED.nodes.registerType("rpi-pibrella out",PibrellaOut);

View File

@ -27,6 +27,8 @@
<p>See <i><a href="http://www.piborg.com/ledborg/install" target="_new">the PiBorg site</a></i> for more information.</p> <p>See <i><a href="http://www.piborg.com/ledborg/install" target="_new">the PiBorg site</a></i> for more information.</p>
<p>You can also now use a <b>msg.payload</b> in the standard hex format "#rrggbb". The clip levels are :</p> <p>You can also now use a <b>msg.payload</b> in the standard hex format "#rrggbb". The clip levels are :</p>
<p><pre>0x00 - 0x57 = off<br/>0x58 - 0xA7 = 50%<br/>0xA8 - 0xFF = fully on</pre></p> <p><pre>0x00 - 0x57 = off<br/>0x58 - 0xA7 = 50%<br/>0xA8 - 0xFF = fully on</pre></p>
<p>You can also use the @cheerlight colour names - red, amber, green, blue, cyan, magenta, yeloow, orange, pink, purple,
white, warmwhite, black</p>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">

View File

@ -20,8 +20,7 @@ var fs = require('fs');
// check if /dev/ledborg exists - if not then don't even show the node. // check if /dev/ledborg exists - if not then don't even show the node.
if (!fs.existsSync("/dev/ledborg")) { if (!fs.existsSync("/dev/ledborg")) {
util.log("[78-ledborg.js] Warning: PiBorg hardware : LedBorg not found"); throw "Info : PiBorg hardware : LedBorg not found";
return;
} }
function LedBorgNode(n) { function LedBorgNode(n) {

View File

@ -13,6 +13,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<script type="text/x-red" data-template-name="Discover"> <script type="text/x-red" data-template-name="Discover">
@ -28,27 +29,25 @@
<!-- Next, some simple help text is provided for the node. --> <!-- Next, some simple help text is provided for the node. -->
<script type="text/x-red" data-help-name="Discover"> <script type="text/x-red" data-help-name="Discover">
<p>This node looks for a Philips Hue Bridge in the local network.</p> <p>This node looks for a Philips Hue Bridge in the local network.</p><p> The node has 2 outputs, the first one contains the IP address of the first discovered bridge and the second one the lights registered to that bridge (in JSON format).</p> <p>To use the node you need to have obtained a valid auth token (or username) from your Philips Hue Bridge. Read <a href="http://developers.meethue.com/gettingstarted.html" target="_blank">here</a> on how to do this.</p>
<p> The node has 2 outputs, the first one contains the IP address of the first discovered bridge and the second one the lights registered to that bridge (in JSON format).</p>
<p>To use the node you need to have obtained a valid auth token (or username) from your Philips Hue Bridge. Read <a href="http://developers.meethue.com/gettingstarted.html" target="_blank">here</a> on how to do this.</p>
</script> </script>
<!-- Finally, the node type is registered along with all of its properties --> <!-- Finally, the node type is registered along with all of its properties -->
<script type="text/javascript"> <script type="text/javascript">
RED.nodes.registerType('Discover',{ RED.nodes.registerType('Discover',{
category: 'advanced-input', category: 'advanced-input', // the palette category
color:"#EFEFEF", color:"#EFEFEF",
defaults: { defaults: { // defines the editable properties of the node
name: {value:""}, name: {value:""}, // along with default values.
username: {value:"", required:true} username: {value:"", required:true}
}, },
inputs:1, inputs:1, // set the number of inputs - only 0 or 1
outputs:2, outputs:2, // set the number of outputs - 0 to n
icon: "hue.png", icon: "huediscover.png", // set the icon (held in public/icons)
label: function() { label: function() { // sets the default label contents
return this.name||"Discover"; return this.name||this.topic||"Discover";
}, },
labelStyle: function() { labelStyle: function() { // sets the class to apply to the label
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
} }
}); });

View File

@ -13,6 +13,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<script type="text/x-red" data-template-name="HueNode"> <script type="text/x-red" data-template-name="HueNode">
@ -35,6 +36,11 @@
</select> </select>
</div> </div>
<div class="form-row">
<label for="node-input-brightness"><i class="icon-tag"></i>Change Brightness (0->100):</label>
<input type="text" id="node-input-brightness" placeholder="brightness">
</div>
<div class="form-row"> <div class="form-row">
<label for="node-input-color"><i class="icon-tag"></i>Select color:</label> <label for="node-input-color"><i class="icon-tag"></i>Select color:</label>
<input type="text" id="node-input-color" placeholder="color"> <input type="text" id="node-input-color" placeholder="color">
@ -50,29 +56,38 @@
<script type="text/x-red" data-help-name="HueNode"> <script type="text/x-red" data-help-name="HueNode">
<p>This node implements some basic functionality for managing a Philips Hue wireless Lamp system.</p> <p>This node implements some basic functionality for managing a Philips Hue wireless Lamp system.</p>
<p>To use it you need to have obtained a valid auth token (or username) from your Philips Hue Bridge. Read <a href="http://developers.meethue.com/gettingstarted.html" target="_blank">here</a> on how to do this.</p> <p>To use it you need to have obtained a valid auth token (or username) from your Philips Hue Bridge. Read <a href="http://developers.meethue.com/gettingstarted.html" target="_blank">here</a> on how to do this.</p>
<p>You can enter the ID (1, 2, ...) of a Lamp and turn it ON or OFF and also set its color. </p><p>By setting the status to AUTO, you can set the ON/OFF status as a message payload (e.g., msg.payload="ON") and the color through the message topic (e.g., msg.topic="EBF5FF") on the node input. Please note, in case you use both, the status selection overides the msg.payload!</p><p>Also, if you pass something like msg.payload="ALERT" the Lamp will flash once.</p> <p>You can enter the ID (1, 2, ...) of a Lamp and turn it ON or OFF, set the color and the brightness (0->100). </p><p>By setting the status to AUTO, you can set the lamp parameters using the message on the input node as follows:</p>
<ul>
<li>msg.lamp sets the lamp ID</li>
<li>msg.color sets the lamp color (e.g., msg.color="DF0101" will set the color to red)</li>
<li>msg.brightness sets the lamp brightness (e.g., msg.brightness=50)</li>
<li>msg.payload is used to se the lamp status (on/off/alert) (e.g., msg.payload="alert" will flash the Lamp once</li>
</ul>
<p>Please note, by setting the status to AUTO on the node configuration, the rest of the node parameters are ignored, you need to set all parameters through the message input.</p>
</script> </script>
<!-- Finally, the node type is registered along with all of its properties --> <!-- Finally, the node type is registered along with all of its properties -->
<script type="text/javascript"> <script type="text/javascript">
RED.nodes.registerType('HueNode',{ RED.nodes.registerType('HueNode',{
category: 'advanced-input', category: 'advanced-input', // the palette category
color:"#EFEFEF", color:"#EFEFEF",
defaults: { defaults: { // defines the editable properties of the node
name: {value:""}, name: {value:""}, // along with default values.
username: {value:"", required:true}, username: {value:"", required:true},
discovery_mode: {value: "", required:false}, discovery_mode: {value: "", required:false},
lamp_id: {value:"", required:false}, lamp_id: {value:"", required:false},
color: {value:"EBF5FF"}, color: {value:"EBF5FF"},
brightness: {value:"100"},
lamp_status:{} lamp_status:{}
}, },
inputs:1, inputs:1, // set the number of inputs - only 0 or 1
outputs:1, outputs:1, // set the number of outputs - 0 to n
icon: "hue.png", icon: "huemanage.png", // set the icon (held in public/icons)
label: function() { label: function() { // sets the default label contents
return this.name||"HueNode"; return this.name||this.topic||"HueNode";
}, },
labelStyle: function() { labelStyle: function() { // sets the class to apply to the label
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
} }
}); });

View File

@ -18,14 +18,19 @@
* limitations under the License. * limitations under the License.
**/ **/
//Require node-hue-api //Require node-hue-api
var hue = require("node-hue-api"); var hue = require("node-hue-api");
var HueApi = require("node-hue-api").HueApi; var HueApi = require("node-hue-api").HueApi;
// Require main module
var RED = require(process.env.NODE_RED_HOME+"/red/red"); var RED = require(process.env.NODE_RED_HOME+"/red/red");
//store the IP address of the Hue Gateway //store the IP address of the Hue Gateway
var gw_ipaddress = ""; var gw_ipaddress = "";
var username, lamp_status, lamp_id, color;
var username, lamp_status, lamp_id, color, brightness;
function hexToRgb(hex) { function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
@ -36,21 +41,32 @@ function hexToRgb(hex) {
} : null; } : null;
} }
// The main node definition - most things happen in here // The main node definition - most things happen in here
function HueNode(n) { function HueNode(n) {
// Create a RED node // Create a RED node
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
var node = this;
//get parameters from user //get parameters from user
this.username = n.username; this.username = n.username;
this.lamp_status = n.lamp_status; this.lamp_status = n.lamp_status;
this.lamp_id = n.lamp_id; this.lamp_id = n.lamp_id;
this.color = n.color; this.color = n.color;
var node = this; this.brightness = n.brightness;
// Store local copies of the node configuration (as defined in the .html)
this.topic = n.topic;
var msg = {}; var msg = {};
msg.topic = this.topic;
this.on("input", function(msg){ this.on("input", function(msg){
var myMsg = msg;
//set the lamp status //set the lamp status
//first locate the Hue gateway: //first locate the Hue gateway:
hue.locateBridges(function(err, result) { hue.locateBridges(function(err, result) {
@ -63,35 +79,62 @@ function HueNode(n) {
//save the IP address of the 1st bridge found //save the IP address of the 1st bridge found
this.gw_ipaddress = result[0].ipaddress; this.gw_ipaddress = result[0].ipaddress;
//set light status //set light status
var api = new HueApi(this.gw_ipaddress, node.username); var api = new HueApi(this.gw_ipaddress, node.username);
var lightState = hue.lightState; var lightState = hue.lightState;
var state = lightState.create(); var state = lightState.create();
var status; var status;
if(msg.payload=="ALERT"){ var lamp = -1;
status = "ALERT";
//check for AUTO status (lamp settings set through node input)
if(node.lamp_status=="AUTO") {
var color;
var brightness;
//get lamp id from msg.lamp:
lamp = myMsg.lamp;
//get brightness:
brightness = myMsg.brightness;
//get colour either from msg.color or msg.topic
if(myMsg.color!=null && myMsg.color.length>0) {
color = myMsg.color;
}
else if(myMsg.topic!=null && myMsg.topic.length>0) {
color = myMsg.topic;
} }
else if(node.lamp_status=="ON" || msg.payload=="ON") status = "ON";
else if(node.lamp_status=="OFF" || msg.payload=="OFF") status = "OFF";
if(status=="ALERT") { //check the payload for on/off/alert:
api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done(); //case of ALERT:
if(myMsg.payload=="ALERT" || myMsg.payload=="alert"){
api.setLightState(lamp, state.alert()).then(displayResult).fail(displayError).done();
} }
else if(status=="ON") {
if(node.color==null) { //case of ON:
api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(msg.topic).r,hexToRgb(msg.topic).g,hexToRgb(msg.topic).b)).then(displayResult).fail(displayError).done(); if(myMsg.payload=="ON" || myMsg.payload=="on") {
api.setLightState(lamp, state.on().rgb(hexToRgb(color).r,hexToRgb(color).g,hexToRgb(color).b).brightness(brightness)).then(displayResult).fail(displayError).done();
} }
else { else {
api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b)).then(displayResult).fail(displayError).done(); api.setLightState(lamp, state.off()).then(displayResult).fail(displayError).done();
} }
} }
else { else {
//set lamp according to node settings
if(node.lamp_status=="ON")
api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b).brightness(node.brightness)).then(displayResult).fail(displayError).done();
else
api.setLightState(node.lamp_id, state.off()).then(displayResult).fail(displayError).done(); api.setLightState(node.lamp_id, state.off()).then(displayResult).fail(displayError).done();
} }
msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+status; if(lamp!=-1)
msg2.payload = 'Light with ID: '+lamp+ ' was set to '+myMsg.payload;
else
msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+node.lamp_status;
node.send(msg2); node.send(msg2);
} }
else { else {
@ -104,6 +147,7 @@ function HueNode(n) {
}); });
}); });
this.on("close", function() { this.on("close", function() {
// Called when the node is shutdown - eg on redeploy. // Called when the node is shutdown - eg on redeploy.
// Allows ports to be closed, connections dropped etc. // Allows ports to be closed, connections dropped etc.
@ -121,6 +165,9 @@ var displayError = function(err) {
console.error(err); console.error(err);
}; };
// Register the node by name. This must be called before overriding any of the // Register the node by name. This must be called before overriding any of the
// Node functions. // Node functions.
RED.nodes.registerType("HueNode",HueNode); RED.nodes.registerType("HueNode",HueNode);

View File

@ -118,7 +118,7 @@ function enable(node) {
} else { } else {
node.stag.unnotifyHumidity(function() {}); node.stag.unnotifyHumidity(function() {});
} }
if (node.accelometer){ if (node.accelerometer){
node.stag.notifyAccelerometer(function() {}); node.stag.notifyAccelerometer(function() {});
} else { } else {
node.stag.unnotifyAccelerometer(function() {}); node.stag.unnotifyAccelerometer(function() {});

View File

@ -22,7 +22,7 @@ var plat = require('os').platform();
var pre = "\\\\.\\"; var pre = "\\\\.\\";
if (!plat.match(/^win/)) { if (!plat.match(/^win/)) {
util.log("[26-rawserial.js] Advise: Only really needed for Windows boxes without serialport npm module installed."); util.log("[26-rawserial.js] Info : only really needed for Windows boxes without serialport npm module installed.");
pre = ""; pre = "";
} }

View File

@ -29,7 +29,7 @@
<p>Uses Growl to provide a desktop popup containing the <b>msg.payload</b>. Only useful on the local machine.</p> <p>Uses Growl to provide a desktop popup containing the <b>msg.payload</b>. Only useful on the local machine.</p>
<p>Optionally uses <b>msg.topic</b> as the title.</p> <p>Optionally uses <b>msg.topic</b> as the title.</p>
<p>Uses Growl so should work cross platform but will need pre-reqs installed... see <i><a href="https://npmjs.org/package/growl" target="_new">this link.</a></i></p> <p>Uses Growl so should work cross platform but will need pre-reqs installed... see <i><a href="https://npmjs.org/package/growl" target="_new">this link.</a></i></p>
<p>If installing on Windows you MUST read the install instructions ... especially the bit about adding growlnotify to your path... or it WON'T work.</p> <p>If installing on Windows you MUST read the install instructions ... especially the bit about adding growlnotify to your path... or it WILL NOT work.</p>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">

View File

@ -16,7 +16,7 @@
var RED = require(process.env.NODE_RED_HOME+"/red/red"); var RED = require(process.env.NODE_RED_HOME+"/red/red");
var growl = require('growl'); var growl = require('growl');
var imagefile = process.env.NODE_RED_HOME+"/public/mqtt-node-red.png"; var imagefile = process.env.NODE_RED_HOME+"/public/node-red.png";
function NotifyNode(n) { function NotifyNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);

View File

@ -16,6 +16,17 @@
--> -->
<script type="text/x-red" data-template-name="twilio out"> <script type="text/x-red" data-template-name="twilio out">
<div class="form-row" id="node-input-credentials-row">
<label for="node-input-creds"><i class="icon-folder-close"></i> Credentials</label>
<select id="node-input-creds">
<option value="global">Use global credentials</option>
<option value="local">Use local credentials</option>
</select>
</div>
<div class="form-row" id="node-input-twilio-row">
<label for="node-input-twilio"><i class="icon-user"></i> Twilio</label>
<input type="text" id="node-input-twilio">
</div>
<div class="form-row"> <div class="form-row">
<label for="node-input-number"><i class="icon-envelope"></i> SMS to</label> <label for="node-input-number"><i class="icon-envelope"></i> SMS to</label>
<input type="text" id="node-input-number" placeholder="01234 5678901"> <input type="text" id="node-input-number" placeholder="01234 5678901">
@ -24,26 +35,104 @@
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-tips">Tip - leave Number blank to use <b>msg.topic</b> to set the number.</div>
</script> </script>
<script type="text/x-red" data-help-name="twilio out"> <script type="text/x-red" data-help-name="twilio out">
<p>Uses Twilio to send the <b>msg.payload</b> as a SMS to the configured number.</p> <p>Sends an SMS message using the Twilio service.</p>
<p>Uses <b>msg.topic</b> to set the phone number, if not already set in the properties.</p> <p><code>msg.payload</code> is used as the body of the message. The node can be configured with the number
<p>You MUST configure both your Account SID and the Auth Token. Either into settings.js like this</p> to send the message to. Alternatively, if the number is left blank, it can be set using <code>msg.topic</code>.</p>
<p><pre>twilio: { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN', from:'FROM-NUMBER' },</pre></p> <p>You must have an account with Twilio to use this node. You can register for one <a href="https://www.twilio.com/">here</a>.</p>
<p>Or as a twiliokey.js file in the directory <b>above</b> node-red.<p> <p>You can either set your account details within the node, or provide it globally using either the settings file or a file
<p><pre>module.exports = { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN',from:'FROM-NUMBER' }</pre></p> called 'twiliokey.js' located in the directory above node-red.</p>
<p>To use the settings.js file, add an entry such as:
<pre>twilio: { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN', from:'FROM-NUMBER' }</pre></p>
<p>To use the 'twiliokey.js' file in the directory <b>above</b> node-red, use the following format:
<pre>module.exports = { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN',from:'FROM-NUMBER' }</pre></p>
</script>
<script type="text/x-red" data-template-name="twilio-api">
<div class="form-row">
<label for="node-config-input-sid">Account SID</label>
<input type="text" id="node-config-input-sid">
</div>
<div class="form-row">
<label for="node-config-input-from"><i class="icon-envelope"></i> From</label>
<input type="text" id="node-config-input-from" placeholder="01234 5678901">
</div>
<div class="form-row">
<label for="node-config-input-token"><i class="icon-lock"></i> Token</label>
<input type="password" id="node-config-input-token">
</div>
<div class="form-row">
<label for="node-config-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-config-input-name" placeholder="Name">
</div>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
(function() {
var hasGlobal = false;
$.getJSON('twilio-api/global',function(data) {
hasGlobal = data.hasToken;
});
RED.nodes.registerType('twilio-api',{
category: 'config',
defaults: {
sid: {value:"",required:true},
from: {value:"",required:true},
// token -> credentials
name: { value: ""}
},
label: function() {
return this.name||this.from;
},
oneditprepare: function() {
$.getJSON('twilio-api/'+this.id,function(data) {
if (data.hasToken) {
$('#node-config-input-token').val('__PWRD__');
} else {
$('#node-config-input-token').val('');
}
});
},
oneditsave: function() {
var newToken = $('#node-config-input-token').val();
if (newToken != '__PWRD__') {
var credentials = {};
credentials.token = newToken;
$.ajax({
url: 'twilio-api/'+this.id,
type: 'POST',
data: credentials,
success:function(result){}
});
}
},
ondelete: function() {
$.ajax({
url: 'twilio-api/'+this.id,
type: 'DELETE',
success: function(result) {}
});
}
});
RED.nodes.registerType('twilio out',{ RED.nodes.registerType('twilio out',{
category: 'output', category: 'output',
defaults: { defaults: {
twilio:{type:"twilio-api",validate:function(v) {
return hasGlobal || (v && v!="_ADD_");
}},
number: {value:""}, number: {value:""},
name: {value:""} name: {value:""}
}, },
color:"#ed1c24", color:"#FF595F",
inputs:1, inputs:1,
outputs:0, outputs:0,
icon: "twilio.png", icon: "twilio.png",
@ -53,7 +142,29 @@
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (hasGlobal) {
$("#node-input-creds").change(function() {
var val = $(this).val();
if (val == "global") {
$("#node-input-twilio-row").hide();
} else {
$("#node-input-twilio-row").show();
} }
}); });
$("#node-input-credentials-row").show();
if (!this.twilio) {
$("#node-input-creds").val("global");
} else {
$("#node-input-creds").val("local");
}
$("#node-input-creds").change();
} else {
$("#node-input-credentials-row").hide();
}
}
});
})();
</script> </script>

View File

@ -17,47 +17,97 @@
var RED = require(process.env.NODE_RED_HOME+"/red/red"); var RED = require(process.env.NODE_RED_HOME+"/red/red");
var util = require('util'); var util = require('util');
var twilio = require('twilio');
// Either add a line like this to settings.js
// twilio: { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN',from:'FROM-NUMBER' },
// Or as a twiliokey.js file in the directory ABOVE node-red.
// module.exports = { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN',from:'FROM-NUMBER' }
try { try {
var twiliokey = RED.settings.twilio || require(process.env.NODE_RED_HOME+"/../twiliokey.js"); var twiliokey = RED.settings.twilio || require(process.env.NODE_RED_HOME+"/../twiliokey.js");
} }
catch(err) { catch(err) {
util.log("[56-twilio.js] Error: Failed to load Twilio credentials");
} }
if (twiliokey) { var querystring = require('querystring');
var twilioClient = require('twilio')(twiliokey.account, twiliokey.authtoken);
var fromNumber = twiliokey.from; RED.httpAdmin.get('/twilio-api/global',function(req,res) {
res.send(JSON.stringify({hasToken:!(twiliokey && twiliokey.account && twiliokey.authtoken)}));
});
RED.httpAdmin.get('/twilio-api/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id);
if (credentials) {
res.send(JSON.stringify({hasToken:(credentials.token&&credentials.token!="")}));
} else {
res.send(JSON.stringify({}));
} }
});
RED.httpAdmin.delete('/twilio-api/:id',function(req,res) {
RED.nodes.deleteCredentials(req.params.id);
res.send(200);
});
RED.httpAdmin.post('/twilio-api/:id',function(req,res) {
var body = "";
req.on('data', function(chunk) {
body+=chunk;
});
req.on('end', function(){
var newCreds = querystring.parse(body);
var credentials = RED.nodes.getCredentials(req.params.id)||{};
if (newCreds.token == "") {
delete credentials.token;
} else {
credentials.token = newCreds.token;
}
RED.nodes.addCredentials(req.params.id,credentials);
res.send(200);
});
});
function TwilioAPINode(n) {
RED.nodes.createNode(this,n);
this.sid = n.sid;
this.from = n.from;
this.name = n.name;
var credentials = RED.nodes.getCredentials(n.id);
if (credentials) {
this.token = credentials.token;
}
}
RED.nodes.registerType("twilio-api",TwilioAPINode);
function TwilioOutNode(n) { function TwilioOutNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.number = n.number; this.number = n.number;
this.api = RED.nodes.getNode(n.twilio);
if (this.api) {
this.twilioClient = twilio(this.api.sid,this.api.token);
this.fromNumber = this.api.from;
} else if (twiliokey) {
this.twilioClient = twilio(twiliokey.account, twiliokey.authtoken);
this.fromNumber = twiliokey.from;
} else {
this.error("missing twilio credentials");
return;
}
var node = this; var node = this;
this.on("input",function(msg) { this.on("input",function(msg) {
if (typeof(msg.payload) == 'object') { if (typeof(msg.payload) == 'object') {
msg.payload = JSON.stringify(msg.payload); msg.payload = JSON.stringify(msg.payload);
} }
if (twiliokey) {
try { try {
// Send SMS // Send SMS
var tonum = node.number || msg.topic; var tonum = node.number || msg.topic;
twilioClient.sendMessage( {to: tonum, from: fromNumber, body: msg.payload}, function(err, response) { node.twilioClient.sendMessage( {to: tonum, from: node.fromNumber, body: msg.payload}, function(err, response) {
if (err) node.error(err); if (err) {
//console.log(response);
});
}
catch (err) {
node.error(err); node.error(err);
} }
} //console.log(response);
else { });
node.warn("Twilio credentials not set/found. See node info."); } catch (err) {
node.error(err);
} }
}); });
} }

View File

@ -38,7 +38,7 @@ function SunNode(n) {
var mins2 = times[node.end].getUTCMinutes(); var mins2 = times[node.end].getUTCMinutes();
var e1 = (hour*60+mins) - (hour1*60+mins1); var e1 = (hour*60+mins) - (hour1*60+mins1);
var e2 = (hour*60+mins) - (hour2*60+mins2); var e2 = (hour*60+mins) - (hour2*60+mins2);
var moon = parseInt(SunCalc.getMoonFraction(now)*100)/100; var moon = SunCalc.getMoonIllumination(now).fraction;
msg = { payload:0, topic:"sun", moon:moon }; msg = { payload:0, topic:"sun", moon:moon };
if ((e1 > 0) & (e2 < 0)) { msg.payload = 1; } if ((e1 > 0) & (e2 < 0)) { msg.payload = 1; }
if (oldval == null) { oldval = msg.payload; } if (oldval == null) { oldval = msg.payload; }