From dd79a64de910e8f389fb5daeb9506d81f0ea0559 Mon Sep 17 00:00:00 2001 From: dceejay Date: Mon, 27 Apr 2015 22:24:47 +0100 Subject: [PATCH] remove old hue node and update README (there is a better node-red-contrib-hue node on npm) --- README.md | 33 ++---- hardware/hue/103-hue_discover.html | 54 --------- hardware/hue/103-hue_discover.js | 104 ---------------- hardware/hue/104-hue_manage.html | 103 ---------------- hardware/hue/104-hue_manage.js | 184 ----------------------------- hardware/hue/icons/hue.png | Bin 8876 -> 0 bytes 6 files changed, 13 insertions(+), 465 deletions(-) delete mode 100644 hardware/hue/103-hue_discover.html delete mode 100644 hardware/hue/103-hue_discover.js delete mode 100644 hardware/hue/104-hue_manage.html delete mode 100644 hardware/hue/104-hue_manage.js delete mode 100644 hardware/hue/icons/hue.png diff --git a/README.md b/README.md index 270937d5..67f22b2b 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ A collection of nodes for [Node-RED](http://nodered.org). See below for a list. ## Installation -Most of these nodes are available as npm packages. See the list below for the npm p -ackage names, or [search npm](https://www.npmjs.org/search?q=node-red-node-). +Most of these nodes are available as npm packages. See the list below for the +npm package names, or [search npm](https://www.npmjs.org/search?q=node-red-node-). -To install +To install - change to your Node-RED user directory. - cd node-red - npm install node-red-node-{*filename*} + cd ~/.node-red + npm install node-red-node-{filename} This repository acts as an overall store for these nodes - and is no longer intended as a way to install them - unless you really do want some bloat. @@ -19,15 +19,15 @@ To manually install using this repo: 1. cd into the `nodes` directory of Node-RED 2. Either: - - download the zip of the repository and extract it - - run `git clone https://github.com/node-red/node-red-nodes.git` -3. npm install in any of the node subfolders to install individual node's dependencies + - download the zip of the repository and extract it + - run `git clone https://github.com/node-red/node-red-nodes.git` +3. run `npm install` in any of the node subfolders to install individual node's dependencies ## Contributing Now that we support npm installaton of nodes we recommend people post their own -via [npm](https://www.npmjs.org/). Please read -the [packaging guide notes](http://nodered.org/docs/creating-nodes/packaging.html). +nodes via [npm](https://www.npmjs.org/). Please read the +[packaging guide notes](http://nodered.org/docs/creating-nodes/packaging.html). If you are an IBMer, please contact us directly as the contribution process is slightly different. @@ -37,14 +37,13 @@ our mistakes. If you need to raise a pull request please read our [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md) before doing so. - ## Copyright and license -Copyright 2013,2015 IBM Corp. under [the Apache 2.0 license](LICENSE). +Copyright 2013, 2015 IBM Corp. under [the Apache 2.0 license](LICENSE). # Extra Node Information -NPM name - File-link - Description +**NPM name** - *File-link* - Description ### Analysis @@ -90,11 +89,7 @@ NPM name - File-link - Description **N/A** - *[101-scanBLE](hardware/scanBLE)* - Scans for a particular Bluetooth Low Energy (BLE) device. -**N/A** - *[103-hue_discover](hardware/hue)* - Looks for a Philips Hue Bridge in the local network. - -**N/A** - *[104-hue_manage](hardware/hue)* - Implements some basic functionality for managing a Philips Hue wireless Lamp system. - -### IO +### I/O **node-red-node-stomp** - *[18-stomp](io/stomp)* - A Node-RED node to publish and subscribe to and from a [STOMP server](https://stomp.github.io/implementations.html#STOMP_Servers). @@ -156,8 +151,6 @@ NPM name - File-link - Description **node-red-node-daemon** - *[daemon](utility/daemon)* - starts up (calls) a long running system program and pipes STDIN, STDOUT and STDERR to and from that process. Good for monitoring long running command line applications, - - ### Misc **N/A** - *[99-sample](./)* - A sample node with more comments than most to try to help you get started without any other docs... diff --git a/hardware/hue/103-hue_discover.html b/hardware/hue/103-hue_discover.html deleted file mode 100644 index 4d375d8a..00000000 --- a/hardware/hue/103-hue_discover.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - diff --git a/hardware/hue/103-hue_discover.js b/hardware/hue/103-hue_discover.js deleted file mode 100644 index b48294ec..00000000 --- a/hardware/hue/103-hue_discover.js +++ /dev/null @@ -1,104 +0,0 @@ -/** - * philips_hue.js - * Basic functionality for accessing a Philips Hue wireless Lamp - * Allows for bridge/gateway detection and light scanning. - * Requires node-hue-api https://github.com/peter-murray/node-hue-api - * Copyright 2013 Charalampos Doukas - @BuildingIoT - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - - -//Require 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; - -// The main node definition - most things happen in here -function HueNodeDiscovery(n) { - // Create a RED node - RED.nodes.createNode(this,n); - - var node = this; - - //get username from user input - this.username = n.username; - - - // Store local copies of the node configuration (as defined in the .html) - this.topic = n.topic; - - this.on("input", function(msg){ - - //start with detecting the IP address of the Hue gateway in the local network: - hue.locateBridges(function(err, result) { - var msg = {}; - 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; - msg.payload = this.gw_ipaddress; - - //get light info: - var api = new HueApi(this.gw_ipaddress, node.username); - api.lights(function(err, lights) { - var msg2 = {}; - if (err) { throw err; } - var lights_discovered = JSON.stringify(lights, null, 2); - msg2.topic = "Lights"; - msg2.payload = lights_discovered; - node.send([msg, msg2]); - }); - } - else { - //bridge not found: - 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. - // eg: this.client.disconnect(); - }); - - } - - //hue debugging on the output: - var displayResult = function(result) { - console.log(result); -}; - -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("Discover",HueNodeDiscovery); diff --git a/hardware/hue/104-hue_manage.html b/hardware/hue/104-hue_manage.html deleted file mode 100644 index c5c364c1..00000000 --- a/hardware/hue/104-hue_manage.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - diff --git a/hardware/hue/104-hue_manage.js b/hardware/hue/104-hue_manage.js deleted file mode 100644 index fbd564c3..00000000 --- a/hardware/hue/104-hue_manage.js +++ /dev/null @@ -1,184 +0,0 @@ -/** - * philips_hue.js - * Basic functionality for accessing and contolling a Philips Hue wireless Lamp - * Allows for bridge/gateway and light scanning, as well as Light ON/OFF/ALERT status update - * Requires node-hue-api https://github.com/peter-murray/node-hue-api - * Copyright 2013 Charalampos Doukas - @BuildingIoT - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - - -//Require 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, brightness; - -function hexToRgb(hex) { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -} - -function setLights(node, myMsg) { - - var msg2 = {}; - msg2.topic = this.topic; - - //set light status - var api = new HueApi(node.gw_ipaddress, node.username); - var lightState = hue.lightState; - var state = lightState.create(); - - 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; - } - - - //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 { - //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); -} - - -// 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.gw_ipaddress = n.ip_address; - this.color = n.color; - 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){ - var myMsg = msg; - //set the lamp status - if (this.gw_ipaddress) { - setLights(node, myMsg); - } else { - //first locate the Hue gateway: - hue.locateBridges(function(err, result) { - - - 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; - setLights(node, myMsg); - } - 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. - // eg: this.client.disconnect(); - }); - - } - - //hue debugging on the output: - var displayResult = function(result) { - console.log(result); -}; - -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); diff --git a/hardware/hue/icons/hue.png b/hardware/hue/icons/hue.png deleted file mode 100644 index 6a265a2de1e96657421dfedb7ee58816122f57e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8876 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