mirror of
https://github.com/node-red/node-red-nodes.git
synced 2023-10-10 13:36:58 +02:00
commit
de655a6dde
@ -16,13 +16,7 @@
|
||||
|
||||
// Require main module
|
||||
var RED = require(process.env.NODE_RED_HOME + "/red/red");
|
||||
|
||||
// Require bonescript
|
||||
try {
|
||||
var bonescript = require("bonescript");
|
||||
} catch (err) {
|
||||
require("util").log("[145-BBB-hardware] Error: cannot find module 'bonescript'");
|
||||
}
|
||||
var bonescript = require("bonescript");
|
||||
|
||||
// Node constructor for bbb-analogue-in
|
||||
function AnalogueInputNode(n) {
|
||||
@ -46,7 +40,7 @@ function AnalogueInputNode(n) {
|
||||
// Variables used for input averaging
|
||||
var sum; // accumulates the input readings to be averaged
|
||||
var count; // keep track of the number of measurements made
|
||||
|
||||
|
||||
// The callback function for analogRead. Accumulates the required number of
|
||||
// measurements, then divides the total number, applies output scaling and
|
||||
// sends the result
|
||||
@ -113,11 +107,11 @@ function DiscreteInputNode(n) {
|
||||
this.starting = true;
|
||||
this.debouncing = false; // True after a change of state while waiting for the 7ms debounce time to elapse
|
||||
this.debounceTimer = null;
|
||||
|
||||
|
||||
// Define 'node' to allow us to access 'this' from within callbacks
|
||||
var node = this;
|
||||
|
||||
// This function is called by the input pin change-of-state interrupt. If
|
||||
// This function is called by the input pin change-of-state interrupt. If
|
||||
// debounce is disabled, send the output message. Otherwise, if we are
|
||||
// currently debouncing, ignore this interrupt. If we are not debouncing,
|
||||
// schedule a re-read of the input pin in 7ms time, and set the debouncing flag
|
||||
@ -146,7 +140,7 @@ function DiscreteInputNode(n) {
|
||||
sendStateMessage(x);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This function is called when either the interruptCallback or the debounceCallback
|
||||
// have determined we have a 'genuine' change of state. Update the currentState and
|
||||
// ActiveTime variables, and send a message on the first output with the new state
|
||||
@ -165,7 +159,7 @@ function DiscreteInputNode(n) {
|
||||
node.send([msg, null]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This function is called by the timer. It updates the ActiveTime variables, and sends a
|
||||
// message on the second output with the latest value of the total active time, in seconds
|
||||
var timerCallback = function () {
|
||||
@ -270,7 +264,7 @@ function PulseInputNode(n) {
|
||||
// Define 'node' to allow us to access 'this' from within callbacks
|
||||
var node = this;
|
||||
|
||||
// Called by the edge or pulse interrupt. If this is a valid interrupt, record the
|
||||
// Called by the edge or pulse interrupt. If this is a valid interrupt, record the
|
||||
// pulse time and count the pulse
|
||||
var interruptCallback = function (x) {
|
||||
if (x.value !== undefined) {
|
||||
@ -350,12 +344,12 @@ function DiscreteOutputNode(n) {
|
||||
this.defaultState = Number(n.defaultState); // What state to set up as
|
||||
this.inverting = n.inverting;
|
||||
this.toggle = n.toggle;
|
||||
|
||||
|
||||
// Working variables
|
||||
this.currentState = this.defaultState;
|
||||
|
||||
|
||||
var node = this;
|
||||
|
||||
|
||||
// If the input message paylod is numeric, values > 0.5 are 'true', otherwise use
|
||||
// the truthiness of the payload. Apply the inversion flag before setting the output
|
||||
var inputCallback = function (msg) {
|
||||
@ -378,7 +372,7 @@ function DiscreteOutputNode(n) {
|
||||
node.send({ topic:node.topic, payload:newState });
|
||||
node.currentState = newState;
|
||||
};
|
||||
|
||||
|
||||
// If we have a valid pin, set it as an output and set the default state
|
||||
if (["P8_7", "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15",
|
||||
"P8_16", "P8_17", "P8_18", "P8_19", "P8_26", "P9_11", "P9_12", "P9_13", "P9_14",
|
||||
@ -407,12 +401,12 @@ function PulseOutputNode(n) {
|
||||
this.defaultState = this.pulseState === 1 ? 0 : 1;
|
||||
this.retriggerable = n.retriggerable;
|
||||
this.pulseTime = n.pulseTime * 1000; // Pulse width in milliseconds
|
||||
|
||||
|
||||
// Working variables
|
||||
this.pulseTimer = null; // Non-null while a pulse is being generated
|
||||
|
||||
|
||||
var node = this;
|
||||
|
||||
|
||||
// Generate a pulse in response to an input message. If the topic includes the text
|
||||
// 'time' (case insensitive) and the payload is numeric, use this value as the
|
||||
// pulse time. Otherwise use the value from the properties dialog.
|
||||
@ -444,14 +438,14 @@ function PulseOutputNode(n) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// At the end of the pulse, restore the default state and set the timer to null
|
||||
var endPulseCallback = function () {
|
||||
node.pulseTimer = null;
|
||||
bonescript.digitalWrite(node.pin, node.defaultState);
|
||||
node.send({ topic:node.topic, payload:node.defaultState });
|
||||
};
|
||||
|
||||
|
||||
// If we have a valid pin, set it as an output and set the default state
|
||||
if (["P8_7", "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15",
|
||||
"P8_16", "P8_17", "P8_18", "P8_19", "P8_26", "P9_11", "P9_12", "P9_13", "P9_14",
|
||||
|
@ -52,10 +52,11 @@
|
||||
</script>
|
||||
|
||||
<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>You may also enable the input pullup resitor if required.</p>
|
||||
<p>The <b>msg.topic</b> is set to <i>pi/{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>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 resistor if required.</p>
|
||||
<p>The <b>msg.topic</b> is set to <i>piface/{the pin number}</i></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 type="text/javascript">
|
||||
@ -103,9 +104,9 @@
|
||||
</script>
|
||||
|
||||
<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>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.</p>
|
||||
<p>Raspberry Pi PiFace output node. The PiFace board must be fitted.</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>Requires the WiringPi gpio command in order to work.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -57,6 +57,33 @@ var pintable = {
|
||||
"LED 6":"206",
|
||||
"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) {
|
||||
RED.nodes.createNode(this,n);
|
||||
@ -76,7 +103,7 @@ function PiFACEInNode(n) {
|
||||
var previousState = node.buttonState;
|
||||
node.buttonState = Number(stdout);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
111
hardware/Pi/38-rpi-pibrella.html
Normal file
111
hardware/Pi/38-rpi-pibrella.html
Normal 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>
|
172
hardware/Pi/38-rpi-pibrella.js
Normal file
172
hardware/Pi/38-rpi-pibrella.js
Normal 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);
|
@ -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>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>You can also use the @cheerlight colour names - red, amber, green, blue, cyan, magenta, yeloow, orange, pink, purple,
|
||||
white, warmwhite, black</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -20,8 +20,7 @@ var fs = require('fs');
|
||||
|
||||
// check if /dev/ledborg exists - if not then don't even show the node.
|
||||
if (!fs.existsSync("/dev/ledborg")) {
|
||||
util.log("[78-ledborg.js] Warning: PiBorg hardware : LedBorg not found");
|
||||
return;
|
||||
throw "Info : PiBorg hardware : LedBorg not found";
|
||||
}
|
||||
|
||||
function LedBorgNode(n) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="Discover">
|
||||
@ -28,27 +29,25 @@
|
||||
|
||||
<!-- Next, some simple help text is provided for the node. -->
|
||||
<script type="text/x-red" data-help-name="Discover">
|
||||
<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>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>
|
||||
</script>
|
||||
|
||||
<!-- Finally, the node type is registered along with all of its properties -->
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('Discover',{
|
||||
category: 'advanced-input',
|
||||
category: 'advanced-input', // the palette category
|
||||
color:"#EFEFEF",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
defaults: { // defines the editable properties of the node
|
||||
name: {value:""}, // along with default values.
|
||||
username: {value:"", required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:2,
|
||||
icon: "hue.png",
|
||||
label: function() {
|
||||
return this.name||"Discover";
|
||||
inputs:1, // set the number of inputs - only 0 or 1
|
||||
outputs:2, // set the number of outputs - 0 to n
|
||||
icon: "huediscover.png", // set the icon (held in public/icons)
|
||||
label: function() { // sets the default label contents
|
||||
return this.name||this.topic||"Discover";
|
||||
},
|
||||
labelStyle: function() {
|
||||
labelStyle: function() { // sets the class to apply to the label
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
@ -13,6 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="HueNode">
|
||||
@ -35,6 +36,11 @@
|
||||
</select>
|
||||
</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">
|
||||
<label for="node-input-color"><i class="icon-tag"></i>Select color:</label>
|
||||
<input type="text" id="node-input-color" placeholder="color">
|
||||
@ -50,29 +56,38 @@
|
||||
<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>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>
|
||||
|
||||
<!-- Finally, the node type is registered along with all of its properties -->
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('HueNode',{
|
||||
category: 'advanced-input',
|
||||
category: 'advanced-input', // the palette category
|
||||
color:"#EFEFEF",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
defaults: { // defines the editable properties of the node
|
||||
name: {value:""}, // along with default values.
|
||||
username: {value:"", required:true},
|
||||
discovery_mode: {value: "", required:false},
|
||||
lamp_id: {value:"", required:false},
|
||||
color: {value:"EBF5FF"},
|
||||
brightness: {value:"100"},
|
||||
lamp_status:{}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "hue.png",
|
||||
label: function() {
|
||||
return this.name||"HueNode";
|
||||
inputs:1, // set the number of inputs - only 0 or 1
|
||||
outputs:1, // set the number of outputs - 0 to n
|
||||
icon: "huemanage.png", // set the icon (held in public/icons)
|
||||
label: function() { // sets the default label contents
|
||||
return this.name||this.topic||"HueNode";
|
||||
},
|
||||
labelStyle: function() {
|
||||
labelStyle: function() { // sets the class to apply to the label
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
@ -18,14 +18,19 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
//Require node-hue-api
|
||||
var hue = require("node-hue-api");
|
||||
var HueApi = require("node-hue-api").HueApi;
|
||||
|
||||
// Require main module
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
|
||||
//store the IP address of the Hue Gateway
|
||||
var gw_ipaddress = "";
|
||||
var username, lamp_status, lamp_id, color;
|
||||
|
||||
|
||||
var username, lamp_status, lamp_id, color, brightness;
|
||||
|
||||
function hexToRgb(hex) {
|
||||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
@ -36,74 +41,113 @@ function hexToRgb(hex) {
|
||||
} : null;
|
||||
}
|
||||
|
||||
|
||||
// The main node definition - most things happen in here
|
||||
function HueNode(n) {
|
||||
// Create a RED node
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
var node = this;
|
||||
|
||||
//get parameters from user
|
||||
this.username = n.username;
|
||||
this.lamp_status = n.lamp_status;
|
||||
this.lamp_id = n.lamp_id;
|
||||
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 = {};
|
||||
|
||||
msg.topic = this.topic;
|
||||
|
||||
this.on("input", function(msg){
|
||||
//set the lamp status
|
||||
//first locate the Hue gateway:
|
||||
hue.locateBridges(function(err, result) {
|
||||
var myMsg = msg;
|
||||
//set the lamp status
|
||||
//first locate the Hue gateway:
|
||||
hue.locateBridges(function(err, result) {
|
||||
|
||||
var msg2 = {};
|
||||
msg2.topic = this.topic;
|
||||
if (err) throw err;
|
||||
//check for found bridges
|
||||
if(result[0]!=null) {
|
||||
//save the IP address of the 1st bridge found
|
||||
this.gw_ipaddress = result[0].ipaddress;
|
||||
var msg2 = {};
|
||||
msg2.topic = this.topic;
|
||||
if (err) throw err;
|
||||
//check for found bridges
|
||||
if(result[0]!=null) {
|
||||
//save the IP address of the 1st bridge found
|
||||
this.gw_ipaddress = result[0].ipaddress;
|
||||
|
||||
|
||||
//set light status
|
||||
var api = new HueApi(this.gw_ipaddress, node.username);
|
||||
var lightState = hue.lightState;
|
||||
var state = lightState.create();
|
||||
//set light status
|
||||
var api = new HueApi(this.gw_ipaddress, node.username);
|
||||
var lightState = hue.lightState;
|
||||
var state = lightState.create();
|
||||
|
||||
var status;
|
||||
if(msg.payload=="ALERT"){
|
||||
status = "ALERT";
|
||||
}
|
||||
else if(node.lamp_status=="ON" || msg.payload=="ON") status = "ON";
|
||||
else if(node.lamp_status=="OFF" || msg.payload=="OFF") status = "OFF";
|
||||
var status;
|
||||
var lamp = -1;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
|
||||
if(status=="ALERT") {
|
||||
api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done();
|
||||
}
|
||||
else if(status=="ON") {
|
||||
if(node.color==null) {
|
||||
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();
|
||||
//check the payload for on/off/alert:
|
||||
//case of ALERT:
|
||||
if(myMsg.payload=="ALERT" || myMsg.payload=="alert"){
|
||||
api.setLightState(lamp, state.alert()).then(displayResult).fail(displayError).done();
|
||||
}
|
||||
|
||||
//case of ON:
|
||||
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 {
|
||||
api.setLightState(lamp, state.off()).then(displayResult).fail(displayError).done();
|
||||
}
|
||||
|
||||
}
|
||||
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();
|
||||
//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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
api.setLightState(node.lamp_id, state.off()).then(displayResult).fail(displayError).done();
|
||||
//bridge not found:
|
||||
var msg = {};
|
||||
msg.payload = "Bridge not found!";
|
||||
node.send(msg);
|
||||
}
|
||||
|
||||
msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+status;
|
||||
node.send(msg2);
|
||||
}
|
||||
else {
|
||||
//bridge not found:
|
||||
var msg = {};
|
||||
msg.payload = "Bridge not found!";
|
||||
node.send(msg);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
this.on("close", function() {
|
||||
// Called when the node is shutdown - eg on redeploy.
|
||||
// Allows ports to be closed, connections dropped etc.
|
||||
@ -121,6 +165,9 @@ var displayError = function(err) {
|
||||
console.error(err);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Register the node by name. This must be called before overriding any of the
|
||||
// Node functions.
|
||||
RED.nodes.registerType("HueNode",HueNode);
|
||||
|
@ -118,7 +118,7 @@ function enable(node) {
|
||||
} else {
|
||||
node.stag.unnotifyHumidity(function() {});
|
||||
}
|
||||
if (node.accelometer){
|
||||
if (node.accelerometer){
|
||||
node.stag.notifyAccelerometer(function() {});
|
||||
} else {
|
||||
node.stag.unnotifyAccelerometer(function() {});
|
||||
|
@ -21,8 +21,8 @@ var fs = require('fs');
|
||||
var plat = require('os').platform();
|
||||
var pre = "\\\\.\\";
|
||||
|
||||
if (! plat.match(/^win/)) {
|
||||
util.log("[26-rawserial.js] Advise: Only really needed for Windows boxes without serialport npm module installed.");
|
||||
if (!plat.match(/^win/)) {
|
||||
util.log("[26-rawserial.js] Info : only really needed for Windows boxes without serialport npm module installed.");
|
||||
pre = "";
|
||||
}
|
||||
|
||||
|
@ -26,10 +26,10 @@
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="notify">
|
||||
<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>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>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>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 WILL NOT work.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -16,24 +16,24 @@
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
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) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.title = n.title;
|
||||
var node = this;
|
||||
this.on("input",function(msg) {
|
||||
var titl = this.title||msg.topic;
|
||||
if (typeof(msg.payload) == 'object') {
|
||||
msg.payload = JSON.stringify(msg.payload);
|
||||
}
|
||||
if (typeof(titl) != 'undefined') {
|
||||
growl(msg.payload, { title: titl, image: imagefile });
|
||||
}
|
||||
else {
|
||||
growl(msg.payload, { image: imagefile });
|
||||
}
|
||||
});
|
||||
RED.nodes.createNode(this,n);
|
||||
this.title = n.title;
|
||||
var node = this;
|
||||
this.on("input",function(msg) {
|
||||
var titl = this.title || msg.topic;
|
||||
if (typeof(msg.payload) == 'object') {
|
||||
msg.payload = JSON.stringify(msg.payload);
|
||||
}
|
||||
if (typeof(titl) != 'undefined') {
|
||||
growl(msg.payload, { title: titl, image: imagefile });
|
||||
}
|
||||
else {
|
||||
growl(msg.payload, { image: imagefile });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("notify",NotifyNode);
|
||||
|
@ -16,6 +16,17 @@
|
||||
-->
|
||||
|
||||
<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">
|
||||
<label for="node-input-number"><i class="icon-envelope"></i> SMS to</label>
|
||||
<input type="text" id="node-input-number" placeholder="01234 5678901">
|
||||
@ -24,36 +35,136 @@
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-tips">Tip - leave Number blank to use <b>msg.topic</b> to set the number.</div>
|
||||
</script>
|
||||
|
||||
<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>Uses <b>msg.topic</b> to set the phone number, if not already set in the properties.</p>
|
||||
<p>You MUST configure both your Account SID and the Auth Token. Either into settings.js like this</p>
|
||||
<p><pre>twilio: { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN', from:'FROM-NUMBER' },</pre></p>
|
||||
<p>Or as a twiliokey.js file in the directory <b>above</b> node-red.<p>
|
||||
<p><pre>module.exports = { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN',from:'FROM-NUMBER' }</pre></p>
|
||||
<p>Sends an SMS message using the Twilio service.</p>
|
||||
<p><code>msg.payload</code> is used as the body of the message. The node can be configured with the number
|
||||
to send the message to. Alternatively, if the number is left blank, it can be set using <code>msg.topic</code>.</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>You can either set your account details within the node, or provide it globally using either the settings file or a file
|
||||
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 type="text/javascript">
|
||||
RED.nodes.registerType('twilio out',{
|
||||
category: 'output',
|
||||
defaults: {
|
||||
number: {value:""},
|
||||
name: {value:""}
|
||||
},
|
||||
color:"#ed1c24",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "twilio.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.title||"twilio";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
(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',{
|
||||
category: 'output',
|
||||
defaults: {
|
||||
twilio:{type:"twilio-api",validate:function(v) {
|
||||
return hasGlobal || (v && v!="_ADD_");
|
||||
}},
|
||||
number: {value:""},
|
||||
name: {value:""}
|
||||
},
|
||||
color:"#FF595F",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "twilio.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.title||"twilio";
|
||||
},
|
||||
labelStyle: function() {
|
||||
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>
|
||||
|
@ -17,47 +17,97 @@
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
var util = require('util');
|
||||
|
||||
// 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' }
|
||||
var twilio = require('twilio');
|
||||
|
||||
try {
|
||||
var twiliokey = RED.settings.twilio || require(process.env.NODE_RED_HOME+"/../twiliokey.js");
|
||||
}
|
||||
catch(err) {
|
||||
util.log("[56-twilio.js] Error: Failed to load Twilio credentials");
|
||||
}
|
||||
|
||||
if (twiliokey) {
|
||||
var twilioClient = require('twilio')(twiliokey.account, twiliokey.authtoken);
|
||||
var fromNumber = twiliokey.from;
|
||||
}
|
||||
var querystring = require('querystring');
|
||||
|
||||
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) {
|
||||
RED.nodes.createNode(this,n);
|
||||
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;
|
||||
this.on("input",function(msg) {
|
||||
if (typeof(msg.payload) == 'object') {
|
||||
msg.payload = JSON.stringify(msg.payload);
|
||||
}
|
||||
if (twiliokey) {
|
||||
try {
|
||||
// Send SMS
|
||||
var tonum = node.number || msg.topic;
|
||||
twilioClient.sendMessage( {to: tonum, from: fromNumber, body: msg.payload}, function(err, response) {
|
||||
if (err) node.error(err);
|
||||
//console.log(response);
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
node.error(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
node.warn("Twilio credentials not set/found. See node info.");
|
||||
try {
|
||||
// Send SMS
|
||||
var tonum = node.number || msg.topic;
|
||||
node.twilioClient.sendMessage( {to: tonum, from: node.fromNumber, body: msg.payload}, function(err, response) {
|
||||
if (err) {
|
||||
node.error(err);
|
||||
}
|
||||
//console.log(response);
|
||||
});
|
||||
} catch (err) {
|
||||
node.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ function SunNode(n) {
|
||||
var mins2 = times[node.end].getUTCMinutes();
|
||||
var e1 = (hour*60+mins) - (hour1*60+mins1);
|
||||
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 };
|
||||
if ((e1 > 0) & (e2 < 0)) { msg.payload = 1; }
|
||||
if (oldval == null) { oldval = msg.payload; }
|
||||
|
Loading…
Reference in New Issue
Block a user