├── .gitignore ├── LICENSE ├── README.md ├── docs ├── check_smartapp_browser.png ├── config.png ├── config_token.png ├── developer_smartapp_verify.png ├── donation.png └── nodered_menu.png ├── package-lock.json ├── package.json ├── smartapp └── webhook.groovy └── smartthings ├── icons ├── accel.png ├── axis.png ├── battery.png ├── button.png ├── config.png ├── energy.png ├── events.png ├── humidity.png ├── illuminance.png ├── light.png ├── lock.png ├── modes.png ├── motion.png ├── onoff.png ├── openclose.png ├── power.png ├── presence.png ├── scene.png ├── smoke.png ├── status.png ├── temperature.png ├── thermostat.png └── water.png ├── smartthings-accel.html ├── smartthings-accel.js ├── smartthings-battery.html ├── smartthings-battery.js ├── smartthings-button.html ├── smartthings-button.js ├── smartthings-color-temperature.html ├── smartthings-color-temperature.js ├── smartthings-color.html ├── smartthings-color.js ├── smartthings-common.js ├── smartthings-config.html ├── smartthings-config.js ├── smartthings-energy-meter.html ├── smartthings-energy-meter.js ├── smartthings-events.html ├── smartthings-events.js ├── smartthings-humidity.html ├── smartthings-humidity.js ├── smartthings-illuminance.html ├── smartthings-illuminance.js ├── smartthings-level.html ├── smartthings-level.js ├── smartthings-lock.html ├── smartthings-lock.js ├── smartthings-modes.html ├── smartthings-modes.js ├── smartthings-motion.html ├── smartthings-motion.js ├── smartthings-onoff.html ├── smartthings-onoff.js ├── smartthings-openclose.html ├── smartthings-openclose.js ├── smartthings-power-meter.html ├── smartthings-power-meter.js ├── smartthings-presence.html ├── smartthings-presence.js ├── smartthings-scene.html ├── smartthings-scene.js ├── smartthings-smoke.html ├── smartthings-smoke.js ├── smartthings-status.html ├── smartthings-status.js ├── smartthings-temperature.html ├── smartthings-temperature.js ├── smartthings-thermostat.html ├── smartthings-thermostat.js ├── smartthings-threeaxis.html ├── smartthings-threeaxis.js ├── smartthings-water.html └── smartthings-water.js /.gitignore: -------------------------------------------------------------------------------- 1 | .git 2 | node_modules/ 3 | node_modules/* 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Robert Henjes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-red-contrib-smartthings 2 | 3 | [![Donate](/docs/donation.png?raw=true)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=65XBWNBZ69ZP4¤cy_code=USD&source=url) 4 | 5 | This is a smartthings plugin to NodeRed. It allows you to control your devices and get their status using NodeRed. 6 | 7 | # Installing 8 | 9 | ``` 10 | npm install node-red-contrib-smartthings 11 | ``` 12 | 13 | or add to your package.json 14 | 15 | ``` 16 | "node-red-contrib-smartthings": "*" 17 | ``` 18 | 19 | to use the git version, add to your package.json 20 | 21 | ``` 22 | "node-red-contrib-smartthings": "https://github.com/otaviojr/node-red-contrib-smartthings.git" 23 | ``` 24 | 25 | this is how it will looks like: 26 | 27 | ![Menu](/docs/nodered_menu.png?raw=true "Menu") 28 | 29 | ***Icon made by [Freepik](https://www.freepik.com/home) from [www.flaticon.com](https://www.flaticon.com)*** 30 | 31 | # Configuring 32 | 33 | Every device node will have an **Account** property which must be configured. 34 | 35 | You only have to create this configuration once and use it in all device nodes. 36 | 37 | Configuration Node Edit Window: 38 | 39 | ![Configuration Node](/docs/config.png?raw=true "Configuration Node") 40 | ![Configuration Node](/docs/config_token.png?raw=true "Configuration Node") 41 | 42 | As you can see, the only relevant information here is a **token** 43 | 44 | # Token 45 | 46 | In order to allow the plugin to have access to your devices using Smartthings API 47 | you must provide a **token** 48 | 49 | You can get a Smartthings Token here: 50 | [https://account.smartthings.com/tokens](https://account.smartthings.com/tokens) 51 | 52 | # SmartApp 53 | 54 | This module works as a SmartApp to receive events back from smartthings. 55 | 56 | **Keep in mind that your nodered instance must be installed with a public IP 57 | address, a domain, and a valid SSL certificate. Without those, smartthings will 58 | not be able to send us any event.** 59 | 60 | *Check the "Using Dynamic IP's" topic below to use a dynamic IP address.* 61 | 62 | The SmartApp can be registered at this address: [Samsung Developer Portal](https://smartthings.developer.samsung.com/) 63 | 64 | To install the SmartApp you can follow these steps: 65 | 66 | 1. Access [Samsung Developer Portal](https://smartthings.developer.samsung.com/) 67 | 2. Create a new Project 68 | 3. Select the "Automation for the Smartthings App" option 69 | 4. Give your project a name 70 | 5. Click on the "Register App" button 71 | 6. Select the "WebHook Endpoint" option 72 | 7. The target URL will be your nodered domain, with https, port, if necessary, 73 | and the path to your SmartApp. It should be something like that: https://your-nodered-domain:your-nodered-server-port/smartthings/smartapp. 74 | 8. Give your App a Display Name. That will be what you will see at the SmartThings App. 75 | 9. Select all permissions. 76 | 10. Finish the process and go to the Project Overview. 77 | 11. Change SmartApp status from "Develop" to "Deployed to test" 78 | 79 | After all those procedures, your app should be OK. 80 | 81 | **Check to see if Smartthings have reached your SmartApp endpoint URL** 82 | 83 | If it have not, you will see something like this at the Project Overview Page 84 | 85 | ![Verify Warning](/docs/developer_smartapp_verify.png?raw=true "Verify") 86 | 87 | You need to verify your address until SmartThings remove this warning. 88 | 89 | You can use your browser to check if your SmartApp is acessible: 90 | 91 | ![Check SmartApp URL](/docs/check_smartapp_browser.png?raw=true "Verify") 92 | 93 | # Smartthings app must be in developer mode 94 | 95 | **To see it in your SmartThings app, you need to make sure it is in developer mode.** 96 | 97 | To put your Smartthings App in developer mode, you need to press and hold the "About SmartThings" option 98 | on the menu for 5 seconds. The option to activate the developer mode should appears after that. 99 | 100 | Enable it, and you should be good to go. 101 | 102 | # Using Dynamic IP's 103 | 104 | Some dynamic ip's dns providers offers SSL certificates for free. 105 | 106 | It is the case of: 107 | 108 | [NoIP](https://www.noip.com). 109 | 110 | You can use them to have a domain with a valid SSL certificate. That should be enough to 111 | make your NodeRed instance visible to SmartThings network. 112 | 113 | Or, you can use let's encrypt to create a certificate for almost any DDNS provider. 114 | 115 | In some countries, providers block the 80 and 443 ports on dynamic IP addresses. 116 | You must use another port to have external access. 117 | 118 | # Configuring the SmartApp 119 | 120 | 1. At your SmartThings App you need to create a new automation, at the discovery panel, 121 | you will see the NodeRed SmartApp, with tha name you choose when registering the SmartApp. 122 | 2. Click on it and select all devices SmartThings should notify you. 123 | 124 | **Only the selected devices will send events back to NodeRed. 125 | Those not selected will not have theirs status updated.** 126 | 127 | Sometimes, the device could appears in more than one session. You need to select 128 | it for all sessions. Otherwise, it will receive only the selected event. 129 | For example, a TV will appears in the switch and volume sessions. If you only select it 130 | in the volume session, It will not receive the switch notifications. 131 | 132 | # Device Nodes 133 | 134 | Once in NodeRed at SmartThings group you will see many devices nodes. Switch, Level, 135 | Color, Humidity, Motion, Contact, etc.. 136 | 137 | Every node will keep its state. Every time a device state changes a message will 138 | be send to the output node with the ```msg.topic``` of **device** with all relevant 139 | informations at the ```msg.payload``` property. 140 | 141 | Device changes are received through the SmartApp you set up at SmartThings Developers 142 | Portal. 143 | 144 | All device nodes can receive at its input a message with the ```msg.topic``` of 145 | **update** to force the output of the current saved device state. This is useful when 146 | handling a request, for example. 147 | If you want to pull the current status from SmartThings, you can send a message with the ```msg.topic``` of **pull**; 148 | 149 | Some devices can have their state changed. You can turn on a light, change 150 | level and color, or, open your door. 151 | 152 | For example, to turn on a switch you can send a message to its device node: 153 | 154 | ``` 155 | { 156 | topic: "switch", 157 | payload: { 158 | value: 1 159 | } 160 | } 161 | ``` 162 | 163 | This will turn on the device using Smartthings API and send the current status to the output. 164 | 165 | This will be documented inside the NodeRed help window for each node. 166 | 167 | # Donation 168 | 169 | And... if this helps you to save time and money. Pay me a coffee. :-) 170 | 171 | [![Donate](/docs/donation.png?raw=true)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=65XBWNBZ69ZP4¤cy_code=USD&source=url) 172 | -------------------------------------------------------------------------------- /docs/check_smartapp_browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/docs/check_smartapp_browser.png -------------------------------------------------------------------------------- /docs/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/docs/config.png -------------------------------------------------------------------------------- /docs/config_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/docs/config_token.png -------------------------------------------------------------------------------- /docs/developer_smartapp_verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/docs/developer_smartapp_verify.png -------------------------------------------------------------------------------- /docs/donation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/docs/donation.png -------------------------------------------------------------------------------- /docs/nodered_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/docs/nodered_menu.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-red-contrib-smartthings", 3 | "version": "0.0.43", 4 | "description": "Querying/Controlling Smartthings Devices", 5 | "main": "index.js", 6 | "keywords": [ 7 | "node-red", 8 | "smartthings", 9 | "smarthome", 10 | "smart", 11 | "home" 12 | ], 13 | "engines": { 14 | "node": ">=12.0.0" 15 | }, 16 | "node-red": { 17 | "version": ">=1.2.0", 18 | "nodes": { 19 | "smartthings-accel": "smartthings/smartthings-accel.js", 20 | "smartthings-battery": "smartthings/smartthings-battery.js", 21 | "smartthings-button": "smartthings/smartthings-button.js", 22 | "smartthings-config": "smartthings/smartthings-config.js", 23 | "smartthings-color": "smartthings/smartthings-color.js", 24 | "smartthings-color-temperature": "smartthings/smartthings-color-temperature.js", 25 | "smartthings-energy": "smartthings/smartthings-energy-meter.js", 26 | "smartthings-events": "smartthings/smartthings-events.js", 27 | "smartthings-humidity": "smartthings/smartthings-humidity.js", 28 | "smartthings-illuminance": "smartthings/smartthings-illuminance.js", 29 | "smartthings-level": "smartthings/smartthings-level.js", 30 | "smartthings-lock": "smartthings/smartthings-lock.js", 31 | "smartthings-motion": "smartthings/smartthings-motion.js", 32 | "smartthings-onoff": "smartthings/smartthings-onoff.js", 33 | "smartthings-openclose": "smartthings/smartthings-openclose.js", 34 | "smartthings-temperature": "smartthings/smartthings-temperature.js", 35 | "smartthings-presence": "smartthings/smartthings-presence.js", 36 | "smartthings-power-meter": "smartthings/smartthings-power-meter.js", 37 | "smartthings-thermostat": "smartthings/smartthings-thermostat.js", 38 | "smartthings-three-axis": "smartthings/smartthings-threeaxis.js", 39 | "smartthings-smoke": "smartthings/smartthings-smoke.js", 40 | "smartthings-scene": "smartthings/smartthings-scene.js", 41 | "smartthings-status": "smartthings/smartthings-status.js", 42 | "smartthings-water": "smartthings/smartthings-water.js" 43 | } 44 | }, 45 | "repository": { 46 | "type": "git", 47 | "url": "git+https://github.com/otaviojr/node-red-contrib-smartthings.git" 48 | }, 49 | "bugs": { 50 | "url": "https://github.com/otaviojr/node-red-contrib-smartthings/issues" 51 | }, 52 | "homepage": "https://github.com/otaviojr/node-red-contrib-smartthings", 53 | "author": "Otávio Ribeiro ", 54 | "license": "MIT", 55 | "dependencies": { 56 | "@smartthings/smartapp": "^2.6.2", 57 | "@smartthings/core-sdk": "*", 58 | "http-signature": "*", 59 | "jsbn": "^1.1.0", 60 | "promise": "^8.0.3" 61 | }, 62 | "bundleDependencies": [], 63 | "contributors": [ 64 | "Otávio Ribeiro " 65 | ], 66 | "deprecated": false, 67 | "directories": { 68 | "doc": "docs" 69 | }, 70 | "devDependencies": {}, 71 | "scripts": { 72 | "test": "echo \"Error: no test specified\" && exit 1" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /smartthings/icons/accel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/accel.png -------------------------------------------------------------------------------- /smartthings/icons/axis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/axis.png -------------------------------------------------------------------------------- /smartthings/icons/battery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/battery.png -------------------------------------------------------------------------------- /smartthings/icons/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/button.png -------------------------------------------------------------------------------- /smartthings/icons/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/config.png -------------------------------------------------------------------------------- /smartthings/icons/energy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/energy.png -------------------------------------------------------------------------------- /smartthings/icons/events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/events.png -------------------------------------------------------------------------------- /smartthings/icons/humidity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/humidity.png -------------------------------------------------------------------------------- /smartthings/icons/illuminance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/illuminance.png -------------------------------------------------------------------------------- /smartthings/icons/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/light.png -------------------------------------------------------------------------------- /smartthings/icons/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/lock.png -------------------------------------------------------------------------------- /smartthings/icons/modes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/modes.png -------------------------------------------------------------------------------- /smartthings/icons/motion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/motion.png -------------------------------------------------------------------------------- /smartthings/icons/onoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/onoff.png -------------------------------------------------------------------------------- /smartthings/icons/openclose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/openclose.png -------------------------------------------------------------------------------- /smartthings/icons/power.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/power.png -------------------------------------------------------------------------------- /smartthings/icons/presence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/presence.png -------------------------------------------------------------------------------- /smartthings/icons/scene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/scene.png -------------------------------------------------------------------------------- /smartthings/icons/smoke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/smoke.png -------------------------------------------------------------------------------- /smartthings/icons/status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/status.png -------------------------------------------------------------------------------- /smartthings/icons/temperature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/temperature.png -------------------------------------------------------------------------------- /smartthings/icons/thermostat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/thermostat.png -------------------------------------------------------------------------------- /smartthings/icons/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otaviojr/node-red-contrib-smartthings/8ef97607df2b60a854343f599b72c41fab867603/smartthings/icons/water.png -------------------------------------------------------------------------------- /smartthings/smartthings-accel.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-accel.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsAccelerationNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsAccelerationNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0 19 | }; 20 | 21 | this.reportState = function(send, done, original) { 22 | send = send || function() { node.send.apply(node,arguments) }; 23 | done = done || function() { }; 24 | let msg = { 25 | topic: "device", 26 | payload: { 27 | deviceId: this.device, 28 | deviceType: "acceleration", 29 | name: this.name, 30 | value: this.state.value, 31 | timestamp: new Date().toISOString() 32 | } 33 | }; 34 | 35 | if(original !== undefined){ 36 | original.payload = msg.payload; 37 | Object.assign(msg,original); 38 | } 39 | 40 | send(msg); 41 | done(); 42 | } 43 | 44 | this.setState = function(value, send, done){ 45 | Object.assign(this.state, value); 46 | this.reportState(send, done); 47 | }; 48 | 49 | this.pullState = function(value, send, done){ 50 | this.conf.getDeviceStatus(this.device,"main/capabilities/accelerationSensor").then( (status) => { 51 | console.debug("AccelerationDevice("+this.name+") Status Refreshed"); 52 | console.debug(status); 53 | 54 | current = status["acceleration"]["value"]; 55 | this.setState({ 56 | value: (current.toLowerCase() == "active" ? 1 : 0), 57 | }); 58 | 59 | }).catch( err => { 60 | console.error("Ops... error getting device state (AccelerationDevice)"); 61 | console.error(err); 62 | }); 63 | }; 64 | 65 | if(this.conf && this.device){ 66 | const callback = (evt) => { 67 | console.debug("AccelerationDevice("+this.name+") Callback called"); 68 | console.debug(evt); 69 | if(evt["attribute"] == "acceleration"){ 70 | this.setState({ 71 | value: (evt["value"].toLowerCase() == "active" ? 1 : 0) 72 | }); 73 | } 74 | } 75 | 76 | this.conf.registerCallback(this, this.device, callback); 77 | this.pullState(); 78 | 79 | this.on('input', (msg, send, done) => { 80 | send = send || function() { node.send.apply(node,arguments) }; 81 | done = done || function() { }; 82 | console.debug("Input Message Received"); 83 | console.log(msg); 84 | 85 | if(msg && msg.topic !== undefined){ 86 | switch(msg.topic){ 87 | case "pull": 88 | this.pullState(); 89 | break; 90 | 91 | case "update": 92 | this.reportState(send, done, msg); 93 | break; 94 | 95 | default: 96 | done("Invalid topic"); 97 | break; 98 | } 99 | } else { 100 | done("Invalid message"); 101 | } 102 | }); 103 | 104 | this.on('close', () => { 105 | console.debug("Closed"); 106 | this.conf.unregisterCallback(this, this.device, callback); 107 | }); 108 | } 109 | } 110 | 111 | RED.nodes.registerType("smartthings-node-accel", SmartthingsAccelerationNode); 112 | }; 113 | -------------------------------------------------------------------------------- /smartthings/smartthings-battery.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-battery.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsBatteryNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsBatteryNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0, 19 | unit: "", 20 | }; 21 | 22 | this.reportState = function(send, done, original) { 23 | send = send || function() { node.send.apply(node,arguments) }; 24 | done = done || function() { }; 25 | 26 | let msg = { 27 | topic: "device", 28 | payload: { 29 | deviceId: this.device, 30 | deviceType: "battery", 31 | name: this.name, 32 | value: this.state.value, 33 | unit: this.state.unit, 34 | timestamp: new Date().toISOString() 35 | } 36 | }; 37 | 38 | if(original !== undefined){ 39 | original.payload = msg.payload; 40 | Object.assign(msg,original); 41 | } 42 | 43 | send(msg); 44 | done(); 45 | } 46 | 47 | this.setState = function(value, send, done){ 48 | Object.assign(this.state, value); 49 | this.reportState(send ,done); 50 | }; 51 | 52 | this.pullState = function(){ 53 | this.conf.getDeviceStatus(this.device,"main/capabilities/battery").then( (status) => { 54 | console.debug("BatteryDevice("+this.name+") Status Refreshed"); 55 | console.debug(status); 56 | 57 | this.setState({ 58 | value: parseFloat(status["battery"]["value"]), 59 | unit: status["battery"]["unit"] 60 | }); 61 | 62 | }).catch( err => { 63 | console.error("Ops... error getting device state (BatteryDevice)"); 64 | console.error(err); 65 | }); 66 | }; 67 | 68 | if(this.conf && this.device){ 69 | const callback = (evt) => { 70 | console.debug("BatteryDevice("+this.name+") Callback called"); 71 | console.debug(evt); 72 | if(evt["attribute"] == "battery"){ 73 | this.setState({ 74 | value: parseFloat(evt["value"]) 75 | }); 76 | } 77 | } 78 | 79 | this.conf.registerCallback(this, this.device, callback); 80 | this.pullState(); 81 | 82 | this.on('input', (msg, send, done) => { 83 | send = send || function() { node.send.apply(node,arguments) }; 84 | done = done || function() { }; 85 | 86 | console.debug("Input Message Received"); 87 | console.log(msg); 88 | 89 | if(msg && msg.topic !== undefined){ 90 | switch(msg.topic){ 91 | case "pull": 92 | this.pullState(); 93 | break; 94 | 95 | case "update": 96 | this.reportState(send, done, msg); 97 | break; 98 | 99 | default: 100 | done("Invalid topic") 101 | break; 102 | } 103 | } 104 | done(); 105 | }); 106 | 107 | this.on('close', () => { 108 | console.debug("Closed"); 109 | this.conf.unregisterCallback(this, this.device, callback); 110 | }); 111 | } 112 | } 113 | 114 | RED.nodes.registerType("smartthings-node-battery", SmartthingsBatteryNode); 115 | }; 116 | -------------------------------------------------------------------------------- /smartthings/smartthings-button.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 117 | -------------------------------------------------------------------------------- /smartthings/smartthings-button.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsButtonNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsButtonNode") 11 | 12 | this.conf = RED.nodes.getNode(config.conf); 13 | this.name = config.name; 14 | this.device = config.device; 15 | 16 | this.currentStatus = ""; 17 | this.button = 0; 18 | 19 | this.reportStatus = function(send, done, original) { 20 | send = send || function() { node.send.apply(node,arguments) }; 21 | done = done || function() { }; 22 | let msg = { 23 | topic: "device", 24 | payload: { 25 | deviceId: this.device, 26 | deviceType: "button", 27 | name: this.name, 28 | value: this.currentStatus, 29 | button: this.button, 30 | timestamp: new Date().toISOString() 31 | } 32 | }; 33 | 34 | if(original !== undefined){ 35 | original.payload = msg.payload; 36 | Object.assign(msg,original); 37 | } 38 | 39 | send(msg); 40 | done(); 41 | }; 42 | 43 | this.updateStatus = function(currentStatus, button){ 44 | this.currentStatus = currentStatus; 45 | this.button = button; 46 | this.reportStatus(); 47 | }; 48 | 49 | if(this.conf && this.device){ 50 | const callback = (evt) => { 51 | console.debug("Button("+this.name+") Callback called"); 52 | console.debug(evt); 53 | if(evt["attribute"] == "button"){ 54 | this.updateStatus(evt["value"], evt["button"]); 55 | } 56 | }; 57 | 58 | this.conf.registerCallback(this, this.device, callback); 59 | 60 | this.on('close', () => { 61 | console.debug("Closed"); 62 | this.conf.unregisterCallback(this, this.device, callback); 63 | }); 64 | } 65 | } 66 | 67 | RED.nodes.registerType("smartthings-node-button", SmartthingsButtonNode); 68 | }; 69 | -------------------------------------------------------------------------------- /smartthings/smartthings-color-temperature.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 183 | -------------------------------------------------------------------------------- /smartthings/smartthings-color.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 217 | -------------------------------------------------------------------------------- /smartthings/smartthings-common.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | createEvent: (conf, evt) => { 3 | return new Promise( (resolve, reject) => { 4 | conf.getDevice(evt.deviceId).then( device => { 5 | console.log("Device Info:"); 6 | console.log(device); 7 | 8 | let msg = { 9 | topic: "event", 10 | payload: { 11 | deviceId: evt.deviceId, 12 | deviceType: evt["attribute"].toLowerCase(), 13 | name: device.name, 14 | timestamp: new Date().toISOString() 15 | } 16 | }; 17 | 18 | switch(evt["attribute"].toLowerCase()){ 19 | case "switch": 20 | msg.payload.value = (evt["value"].toLowerCase() === "on" ? 1 : 0); 21 | break; 22 | 23 | case "contact": 24 | if(conf.closeAsActive){ 25 | msg.payload.value = (evt["value"].toLowerCase() === "closed" ? 1 : 0); 26 | } else { 27 | msg.payload.value = (evt["value"].toLowerCase() === "open" ? 1 : 0); 28 | } 29 | break; 30 | 31 | case "motion": 32 | case "acceleration": 33 | msg.payload.value = (evt["value"].toLowerCase() === "active" ? 1 : 0); 34 | break; 35 | 36 | case "lock": 37 | msg.payload.value = (evt["value"].toLowerCase() === "locked" ? 1 : 0); 38 | break; 39 | 40 | case "presence": 41 | msg.payload.value = (evt["value"].toLowerCase() === "present" ? 1 : 0); 42 | break; 43 | 44 | case "smoke": 45 | msg.payload.value = (evt["value"].toLowerCase() === "detected" ? 1 : 0); 46 | break; 47 | 48 | case "water": 49 | msg.payload.value = (evt["value"].toLowerCase() === "wet" ? 1 : 0); 50 | break; 51 | 52 | default: 53 | msg.payload.value = evt["value"]; 54 | break; 55 | } 56 | 57 | resolve(msg); 58 | }).catch( err => { 59 | reject(err); 60 | }); 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /smartthings/smartthings-config.html: -------------------------------------------------------------------------------- 1 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /smartthings/smartthings-energy-meter.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-energy-meter.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsEnergyMeterNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsEnergyMeterNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0, 19 | unit: "", 20 | }; 21 | 22 | this.reportState = function(send, done, original) { 23 | send = send || function() { node.send.apply(node,arguments) }; 24 | done = done || function() { }; 25 | let msg = { 26 | topic: "device", 27 | payload: { 28 | deviceId: this.device, 29 | deviceType: "energy", 30 | name: this.name, 31 | value: this.state.value, 32 | unit: this.state.unit, 33 | timestamp: new Date().toISOString() 34 | } 35 | }; 36 | 37 | if(original !== undefined){ 38 | original.payload = msg.payload; 39 | Object.assign(msg,original); 40 | } 41 | 42 | send(msg); 43 | done(); 44 | } 45 | 46 | this.setState = function(value, send, done){ 47 | Object.assign(this.state, value); 48 | this.reportState(send, done); 49 | }; 50 | 51 | this.pullState = function(){ 52 | this.conf.getDeviceStatus(this.device,"main/capabilities/energyMeter").then( (status) => { 53 | console.debug("EnergyMeterDevice("+this.name+") Status Refreshed"); 54 | console.debug(status); 55 | 56 | this.setState({ 57 | value: parseFloat(status["energy"]["value"]), 58 | unit: status["energy"]["unit"] 59 | }); 60 | 61 | }).catch( err => { 62 | console.error("Ops... error getting device state (EnergyMeterDevice)"); 63 | console.error(err); 64 | }); 65 | }; 66 | 67 | if(this.conf && this.device){ 68 | const callback = (evt) => { 69 | console.debug("EnergyMeterDevice("+this.name+") Callback called"); 70 | console.debug(evt); 71 | if(evt["attribute"] == "energy"){ 72 | this.setState({ 73 | value: parseFloat(evt["value"]) 74 | }); 75 | } 76 | } 77 | 78 | this.conf.registerCallback(this, this.device, callback); 79 | this.pullState(); 80 | 81 | this.on('input', (msg, send, done) => { 82 | send = send || function() { node.send.apply(node,arguments) }; 83 | done = done || function() { }; 84 | console.debug("Input Message Received"); 85 | console.log(msg); 86 | 87 | if(msg && msg.topic !== undefined){ 88 | switch(msg.topic){ 89 | case "pull": 90 | this.pullState(); 91 | break; 92 | 93 | case "update": 94 | this.reportState(send, done, msg); 95 | break; 96 | 97 | default: 98 | done("Invalid Topic"); 99 | break; 100 | } 101 | } else { 102 | done("Invalid Message"); 103 | } 104 | }); 105 | 106 | this.on('close', () => { 107 | console.debug("Closed"); 108 | this.conf.unregisterCallback(this, this.device, callback); 109 | }); 110 | } 111 | } 112 | 113 | RED.nodes.registerType("smartthings-node-energy-meter", SmartthingsEnergyMeterNode); 114 | }; 115 | -------------------------------------------------------------------------------- /smartthings/smartthings-events.html: -------------------------------------------------------------------------------- 1 | 21 | 22 | 36 | 37 | 44 | -------------------------------------------------------------------------------- /smartthings/smartthings-events.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | var Common = require('./smartthings-common.js'); 3 | 4 | module.exports = function(RED) { 5 | 6 | function SmartthingsEventsNode(config) { 7 | RED.nodes.createNode(this, config); 8 | 9 | let node = this; 10 | 11 | console.debug("SmartthingsEventsNode") 12 | console.debug(config); 13 | 14 | this.conf = RED.nodes.getNode(config.conf); 15 | this.name = config.name; 16 | this.closeAsActive = config.closeAsActive; 17 | 18 | this.reportEvent = function(evt, send, done, original){ 19 | send = send || function() { node.send.apply(node,arguments) }; 20 | done = done || function() { }; 21 | 22 | Common.createEvent(this.conf, evt).then( (msg) => { 23 | if(original !== undefined){ 24 | original.payload = msg.payload; 25 | Object.assign(msg,original); 26 | } 27 | 28 | send(msg); 29 | done(); 30 | }).catch( (err) => { 31 | let msg = { 32 | error: { 33 | message: `Unable to receive event: ${err}`, 34 | } 35 | }; 36 | send(msg); 37 | done(); 38 | }); 39 | } 40 | 41 | if(this.conf){ 42 | const callback = (evt) => { 43 | console.debug("EventNode("+this.name+") Callback called"); 44 | console.debug(evt); 45 | 46 | this.reportEvent(evt); 47 | } 48 | 49 | this.conf.registerCallbackHook(this, callback); 50 | 51 | this.on('close', () => { 52 | console.debug("Closed"); 53 | this.conf.unregisterCallbackHook(this, callback); 54 | }); 55 | } 56 | } 57 | 58 | RED.nodes.registerType("smartthings-node-events", SmartthingsEventsNode); 59 | }; 60 | -------------------------------------------------------------------------------- /smartthings/smartthings-humidity.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-humidity.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsHumidityNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsHumidityNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0, 19 | unit: "", 20 | }; 21 | 22 | this.reportState = function(send, done, original) { 23 | send = send || function() { node.send.apply(node,arguments) }; 24 | done = done || function() { }; 25 | let msg = { 26 | topic: "device", 27 | payload: { 28 | deviceId: this.device, 29 | deviceType: "humidity", 30 | name: this.name, 31 | value: this.state.value, 32 | unit: this.state.unit, 33 | timestamp: new Date().toISOString() 34 | } 35 | }; 36 | 37 | if(original !== undefined){ 38 | original.payload = msg.payload; 39 | Object.assign(msg,original); 40 | } 41 | 42 | send(msg); 43 | done(); 44 | } 45 | 46 | this.setState = function(value, send, done){ 47 | Object.assign(this.state, value); 48 | this.reportState(send, done); 49 | }; 50 | 51 | this.pullState = function(){ 52 | this.conf.getDeviceStatus(this.device,"main/capabilities/relativeHumidityMeasurement").then( (status) => { 53 | console.debug("HumidityDevice("+this.name+") Status Refreshed"); 54 | console.debug(status); 55 | 56 | this.setState({ 57 | value: parseFloat(status["humidity"]["value"]), 58 | unit: status["humidity"]["unit"] 59 | }); 60 | 61 | }).catch( err => { 62 | console.error("Ops... error getting device state (HumidityDevice)"); 63 | console.error(err); 64 | }); 65 | }; 66 | 67 | if(this.conf && this.device){ 68 | const callback = (evt) => { 69 | console.debug("HumidityDevice("+this.name+") Callback called"); 70 | console.debug(evt); 71 | if(evt["attribute"] == "humidity"){ 72 | this.setState({ 73 | value: parseFloat(evt["value"]) 74 | }); 75 | } 76 | } 77 | 78 | this.conf.registerCallback(this, this.device, callback); 79 | this.pullState(); 80 | 81 | this.on('input', (msg, send, done) => { 82 | send = send || function() { node.send.apply(node,arguments) }; 83 | done = done || function() { }; 84 | console.debug("Input Message Received"); 85 | console.log(msg); 86 | 87 | if(msg && msg.topic !== undefined){ 88 | switch(msg.topic){ 89 | case "pull": 90 | this.pullState(); 91 | break; 92 | 93 | case "update": 94 | this.reportState(send, done, msg); 95 | break; 96 | 97 | default: 98 | done("Invalid Topic"); 99 | break; 100 | } 101 | } else { 102 | done("Invalid Message"); 103 | } 104 | }); 105 | 106 | this.on('close', () => { 107 | console.debug("Closed"); 108 | this.conf.unregisterCallback(this, this.device, callback); 109 | }); 110 | } 111 | } 112 | 113 | RED.nodes.registerType("smartthings-node-humidity", SmartthingsHumidityNode); 114 | }; 115 | -------------------------------------------------------------------------------- /smartthings/smartthings-illuminance.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-illuminance.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsIlluminanceNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsIlluminanceNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.currentStatus = 0; 18 | this.currentUnit = ""; 19 | 20 | this.reportStatus = function(send, done, original) { 21 | send = send || function() { node.send.apply(node,arguments) }; 22 | done = done || function() { }; 23 | let msg = { 24 | topic: "device", 25 | payload: { 26 | deviceId: this.device, 27 | deviceType: "illuminance", 28 | name: this.name, 29 | value: this.currentStatus, 30 | unit: this.currentUnit, 31 | timestamp: new Date().toISOString() 32 | } 33 | }; 34 | 35 | if(original !== undefined){ 36 | original.payload = msg.payload; 37 | Object.assign(msg,original); 38 | } 39 | 40 | send(msg); 41 | done(); 42 | } 43 | 44 | this.updateStatus = function(currentStatus, currentUnit, send, done){ 45 | this.currentStatus = currentStatus; 46 | this.currentUnit = currentUnit; 47 | this.reportStatus(send, done); 48 | } 49 | 50 | this.pullStatus = function(){ 51 | this.conf.getDeviceStatus(this.device,"main/capabilities/illuminanceMeasurement").then( (status) => { 52 | console.debug("IlluminanceDevice("+this.name+") Status Refreshed"); 53 | console.debug(status); 54 | 55 | current = parseFloat(status["illuminance"]["value"]); 56 | unit = status["illuminance"]["unit"]; 57 | if(current){ 58 | this.updateStatus(current, unit); 59 | } 60 | }).catch( err => { 61 | console.error("Ops... error getting device state (IlluminanceDevice)"); 62 | console.error(err); 63 | }); 64 | } 65 | 66 | if(this.conf && this.device){ 67 | const callback = (evt) => { 68 | console.debug("IlluminanceDevice("+this.name+") Callback called"); 69 | console.debug(evt); 70 | if(evt["attribute"] == "illuminance"){ 71 | this.updateStatus(parseFloat(evt["value"]),evt["unit"]); 72 | } 73 | } 74 | 75 | this.conf.registerCallback(this, this.device, callback); 76 | this.pullState(); 77 | 78 | this.on('input', (msg, send, done) => { 79 | send = send || function() { node.send.apply(node,arguments) }; 80 | done = done || function() { }; 81 | console.debug("Input Message Received"); 82 | console.log(msg); 83 | 84 | if(msg && msg.topic !== undefined){ 85 | switch(msg.topic){ 86 | case "pull": 87 | this.pullStatus(); 88 | break; 89 | 90 | case "update": 91 | this.reportStatus(send, done, msg); 92 | break; 93 | 94 | default: 95 | done("Invalid Topic"); 96 | break; 97 | } 98 | } else { 99 | done("Invalid Message"); 100 | } 101 | }); 102 | 103 | this.on('close', () => { 104 | console.debug("Closed"); 105 | this.conf.unregisterCallback(this, this.device, callback); 106 | }); 107 | } 108 | } 109 | 110 | RED.nodes.registerType("smartthings-node-illuminance", SmartthingsIlluminanceNode); 111 | 112 | }; 113 | -------------------------------------------------------------------------------- /smartthings/smartthings-level.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 154 | -------------------------------------------------------------------------------- /smartthings/smartthings-level.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsLevelNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsLevelNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.currentStatus = 0; 18 | this.currentLevel = 0; 19 | 20 | this.state = { 21 | value: 0, 22 | level: 0, 23 | levelUnit: "" 24 | } 25 | 26 | this.reportState = function(send, done, original) { 27 | send = send || function() { node.send.apply(node,arguments) }; 28 | done = done || function() { }; 29 | let msg = [{ 30 | topic: "device", 31 | payload: { 32 | deviceId: this.device, 33 | deviceType: "switch", 34 | name: this.name, 35 | value: this.state.value, 36 | timestamp: new Date().toISOString() 37 | } 38 | },{ 39 | topic: "device", 40 | payload: { 41 | deviceId: this.device, 42 | deviceType: "level", 43 | name: this.name, 44 | value: this.state.level, 45 | unit: this.state.levelUnit, 46 | timestamp: new Date().toISOString() 47 | } 48 | }]; 49 | 50 | if(original !== undefined){ 51 | msg.forEach( (m) => { 52 | original.payload = m.payload; 53 | Object.assign(m,original); 54 | }); 55 | } 56 | 57 | send(msg); 58 | done(); 59 | } 60 | 61 | this.setState = function(value, send, done) { 62 | Object.assign(this.state, value); 63 | this.reportState(send, done); 64 | } 65 | 66 | this.pullState = function(value, send, done) { 67 | this.conf.getDeviceStatus(this.device,"main").then( (status) => { 68 | console.debug("LevelDevice("+this.name+") Status Refreshed"); 69 | 70 | let state = {}; 71 | 72 | if(status["switch"] !== undefined && status["switch"]["switch"] !== undefined){ 73 | state.value = (status["switch"]["switch"]["value"].toLowerCase() === "on" ? 1 : 0); 74 | } 75 | 76 | if(status["switchLevel"] !== undefined && status["switchLevel"]["level"] !== undefined){ 77 | state.level = status["switchLevel"]["level"]["value"]; 78 | state.levelUnit = status["switchLevel"]["level"]["unit"]; 79 | } 80 | 81 | this.setState(state); 82 | }).catch( err => { 83 | console.error("Ops... error getting device state (LevelDevice)"); 84 | console.error(err); 85 | }); 86 | } 87 | 88 | if(this.conf && this.device){ 89 | const callback = (evt) => { 90 | console.debug("LevelDevice("+this.name+") Callback called"); 91 | console.debug(evt); 92 | 93 | let state = {}; 94 | 95 | switch(evt["attribute"].toLowerCase()){ 96 | case "switch": 97 | state.value = (evt["value"].toLowerCase() === "on" ? 1 : 0); 98 | break; 99 | 100 | case "level": 101 | state.level = evt["value"]; 102 | break; 103 | } 104 | 105 | this.setState(state); 106 | } 107 | 108 | this.conf.registerCallback(this, this.device, callback); 109 | this.pullState(); 110 | 111 | this.on('input', (msg, send, done) => { 112 | send = send || function() { node.send.apply(node,arguments) }; 113 | done = done || function() { }; 114 | console.debug("Input Message Received"); 115 | console.log(msg); 116 | 117 | if(msg && msg.topic !== undefined){ 118 | switch(msg.topic){ 119 | case "pull": 120 | this.pullState(); 121 | break; 122 | 123 | case "update": 124 | this.reportState(send, done, msg); 125 | break; 126 | 127 | case "switch": 128 | this.conf.executeDeviceCommand(this.device,[{ 129 | component: "main", 130 | capability: "switch", 131 | command: (msg.payload.value == 1 ? "on" : "off") 132 | }]).then( (ret) => { 133 | const state = { 134 | value: msg.payload.value 135 | } 136 | this.setState(state, send, done); 137 | }).catch( (ret) => { 138 | console.error("Error updating device"); 139 | done("Error updating device"); 140 | }); 141 | break; 142 | 143 | case "level": 144 | this.conf.executeDeviceCommand(this.device,[{ 145 | component: "main", 146 | capability: "switchLevel", 147 | command: "setLevel", 148 | arguments: [ 149 | msg.payload.value 150 | ] 151 | }]).then( (ret) => { 152 | const state = { 153 | level: msg.payload.value 154 | } 155 | this.setState(state, send, done); 156 | }).catch( (ret) => { 157 | console.error("Error updating device"); 158 | done("Error updating device"); 159 | }); 160 | break; 161 | 162 | default: 163 | done("Invalid topic"); 164 | break; 165 | } 166 | } else { 167 | done("Invalid Message"); 168 | } 169 | }); 170 | 171 | this.on('close', () => { 172 | console.debug("Closed"); 173 | this.conf.unregisterCallback(this, this.device, callback); 174 | }); 175 | } 176 | } 177 | 178 | RED.nodes.registerType("smartthings-node-level", SmartthingsLevelNode); 179 | 180 | }; 181 | -------------------------------------------------------------------------------- /smartthings/smartthings-lock.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 141 | -------------------------------------------------------------------------------- /smartthings/smartthings-lock.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsLockNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsLockNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.currentStatus = 0; 18 | 19 | this.reportStatus = function(send, done, original) { 20 | send = send || function() { node.send.apply(node,arguments) }; 21 | done = done || function() { }; 22 | let msg = { 23 | topic: "device", 24 | payload: { 25 | deviceId: this.device, 26 | deviceType: "lock", 27 | name: this.name, 28 | value: this.currentStatus, 29 | timestamp: new Date().toISOString() 30 | } 31 | }; 32 | 33 | if(original !== undefined){ 34 | original.payload = msg.payload; 35 | Object.assign(msg,original); 36 | } 37 | 38 | send(msg); 39 | done(); 40 | } 41 | 42 | this.updateStatus = function(currentStatus, send, done){ 43 | this.currentStatus = currentStatus; 44 | this.reportStatus(send, done); 45 | } 46 | 47 | this.pullStatus = function(send, done, original){ 48 | this.conf.getDeviceStatus(this.device,"main/capabilities/lock").then( (status) => { 49 | console.debug("LockDevice("+this.name+") Status Refreshed"); 50 | 51 | current = status["lock"]["value"]; 52 | if(current){ 53 | this.updateStatus((current.toLowerCase() == "locked" ? 1 : 0)); 54 | } 55 | }).catch( err => { 56 | console.error("Ops... error getting device state (LockDevice)"); 57 | console.error(err); 58 | }); 59 | } 60 | 61 | if(this.conf && this.device){ 62 | const callback = (evt) => { 63 | console.debug("LockDevice("+this.name+") Callback called"); 64 | console.debug(evt); 65 | if(evt["attribute"] == "lock"){ 66 | this.updateStatus((evt["value"].toLowerCase() === "locked" ? 1 : 0)); 67 | } 68 | } 69 | 70 | this.conf.registerCallback(this, this.device, callback); 71 | this.pullStatus(); 72 | 73 | this.on('input', (msg, send, done) => { 74 | send = send || function() { node.send.apply(node,arguments) }; 75 | done = done || function() { }; 76 | console.debug("Input Message Received"); 77 | if(msg && msg.payload && !isNaN(msg.payload.value) && msg.topic === "lock"){ 78 | this.conf.executeDeviceCommand(this.device,[{ 79 | component: "main", 80 | capability: "lock", 81 | command: (msg.payload.value == 1 ? "lock" : "unlock") 82 | }]).then( (ret) => { 83 | this.updateStatus(msg.payload.value, send, done); 84 | }).catch( (ret) => { 85 | console.error("Error updating device"); 86 | done("Error updating device"); 87 | }); 88 | } else if(msg.topic === "pull"){ 89 | this.pullStatus(); 90 | } else if(msg.topic === "update"){ 91 | this.reportStatus(send, done, msg); 92 | } else { 93 | done("Invalid topic"); 94 | } 95 | }); 96 | 97 | this.on('close', () => { 98 | console.debug("Closed"); 99 | this.conf.unregisterCallback(this, this.device, callback); 100 | }); 101 | } 102 | } 103 | 104 | RED.nodes.registerType("smartthings-node-lock", SmartthingsLockNode); 105 | 106 | }; 107 | -------------------------------------------------------------------------------- /smartthings/smartthings-modes.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 108 | -------------------------------------------------------------------------------- /smartthings/smartthings-modes.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsModeNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsModeNode") 11 | 12 | this.conf = RED.nodes.getNode(config.conf); 13 | this.name = config.name; 14 | this.scene = config.scene; 15 | 16 | if(this.conf && this.scene){ 17 | 18 | this.on('input', (msg, send, done) => { 19 | send = send || function() { node.send.apply(node,arguments) }; 20 | done = done || function() { }; 21 | console.debug("Input Message Received"); 22 | if(msg && msg.topic === "mode"){ 23 | this.conf.executeScene(this.scene).then( (ret) => { 24 | done(); 25 | }).catch( (ret) => { 26 | this.error("Error executing scene"); 27 | done("Error executing scene"); 28 | }); 29 | } 30 | }); 31 | 32 | this.on('close', () => { 33 | console.debug("Closed"); 34 | }); 35 | } 36 | } 37 | 38 | RED.nodes.registerType("smartthings-node-mode", SmartthingsModeNode); 39 | }; 40 | -------------------------------------------------------------------------------- /smartthings/smartthings-motion.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-motion.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsMotionNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsMotionNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.currentStatus = 0; 18 | 19 | this.reportStatus = function(send, done, original){ 20 | send = send || function() { node.send.apply(node,arguments) }; 21 | done = done || function() { }; 22 | let msg = { 23 | topic: "device", 24 | payload: { 25 | deviceId: this.device, 26 | deviceType: "motion", 27 | name: this.name, 28 | value: this.currentStatus, 29 | timestamp: new Date().toISOString() 30 | } 31 | }; 32 | 33 | if(original !== undefined){ 34 | original.payload = msg.payload; 35 | Object.assign(msg,original); 36 | } 37 | 38 | send(msg); 39 | done(); 40 | } 41 | 42 | this.updateStatus = function(currentStatus, send, done){ 43 | this.currentStatus = currentStatus; 44 | this.reportStatus(send, done); 45 | } 46 | 47 | this.pullStatus = function() { 48 | this.conf.getDeviceStatus(this.device,"main/capabilities/motionSensor").then( (status) => { 49 | console.debug("MotionDevice("+this.name+") Status Refreshed"); 50 | console.debug(status); 51 | 52 | current = status["motion"]["value"]; 53 | if(current){ 54 | this.updateStatus((current.toLowerCase() == "active" ? 1 : 0)); 55 | } 56 | }).catch( err => { 57 | console.error("Ops... error getting device state (MotionDevice)"); 58 | console.error(err); 59 | }); 60 | } 61 | 62 | if(this.conf && this.device){ 63 | const callback = (evt) => { 64 | console.debug("MotionDevice("+this.name+") Callback called"); 65 | console.debug(evt); 66 | if(evt["attribute"] == "motion"){ 67 | this.updateStatus((evt["value"].toLowerCase() == "active" ? 1 : 0)); 68 | } 69 | } 70 | 71 | this.conf.registerCallback(this, this.device, callback); 72 | this.pullStatus(); 73 | 74 | this.on('input', (msg, send, done) => { 75 | send = send || function() { node.send.apply(node,arguments) }; 76 | done = done || function() { }; 77 | console.debug("Input Message Received"); 78 | console.log(msg); 79 | 80 | if(msg && msg.topic !== undefined){ 81 | switch(msg.topic){ 82 | case "pull": 83 | this.pullStatus(); 84 | break; 85 | 86 | case "update": 87 | this.reportStatus(send, done, msg); 88 | break; 89 | 90 | default: 91 | done("Invalid Topic") 92 | break; 93 | } 94 | } else { 95 | done("Invalid Message"); 96 | } 97 | }); 98 | 99 | this.on('close', () => { 100 | console.debug("Closed"); 101 | this.conf.unregisterCallback(this, this.device, callback); 102 | }); 103 | } 104 | } 105 | 106 | RED.nodes.registerType("smartthings-node-motion", SmartthingsMotionNode); 107 | 108 | }; 109 | -------------------------------------------------------------------------------- /smartthings/smartthings-onoff.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 141 | -------------------------------------------------------------------------------- /smartthings/smartthings-onoff.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsOnOffNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsOnOffNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.currentStatus = 0; 18 | 19 | this.reportStatus = function(send, done, original) { 20 | send = send || function() { node.send.apply(node,arguments) }; 21 | done = done || function() { }; 22 | let msg = { 23 | topic: "device", 24 | payload: { 25 | deviceId: this.device, 26 | deviceType: "switch", 27 | name: this.name, 28 | value: this.currentStatus, 29 | timestamp: new Date().toISOString() 30 | } 31 | }; 32 | 33 | if(original !== undefined){ 34 | original.payload = msg.payload; 35 | Object.assign(msg,original); 36 | } 37 | 38 | send(msg); 39 | done(); 40 | } 41 | 42 | this.updateStatus = function(currentStatus, send, done){ 43 | this.currentStatus = currentStatus; 44 | this.reportStatus(send, done); 45 | } 46 | 47 | this.pullStatus = function() { 48 | this.conf.getDeviceStatus(this.device,"main/capabilities/switch").then( (status) => { 49 | console.debug("OnOffDevice("+this.name+") Status Refreshed"); 50 | 51 | current = status["switch"]["value"]; 52 | if(current){ 53 | this.updateStatus((current.toLowerCase() == "on" ? 1 : 0)); 54 | } 55 | }).catch( err => { 56 | console.error("Ops... error getting device state (OnOffDevice)"); 57 | console.error(err); 58 | }); 59 | } 60 | 61 | if(this.conf && this.device){ 62 | const callback = (evt) => { 63 | console.debug("OnOffDevice("+this.name+") Callback called"); 64 | console.debug(evt); 65 | if(evt["attribute"] == "switch"){ 66 | this.updateStatus((evt["value"].toLowerCase() === "on" ? 1 : 0)); 67 | } 68 | } 69 | 70 | this.conf.registerCallback(this, this.device, callback); 71 | 72 | this.pullStatus(); 73 | 74 | this.on('input', (msg, send, done) => { 75 | send = send || function() { node.send.apply(node,arguments) }; 76 | done = done || function() { }; 77 | console.debug("Input Message Received"); 78 | console.debug(msg) 79 | if(msg && msg.payload && !isNaN(msg.payload.value) && msg.topic === "switch"){ 80 | this.conf.executeDeviceCommand(this.device,[{ 81 | component: "main", 82 | capability: "switch", 83 | command: (msg.payload.value === 1 ? "on" : "off") 84 | }]).then( (ret) => { 85 | this.updateStatus(msg.payload.value, send, done); 86 | }).catch( (ret) => { 87 | console.error("Error updating device"); 88 | done("Error updating device"); 89 | }); 90 | } else if(msg.topic === "pull"){ 91 | this.pullStatus(); 92 | } else if(msg.topic === "update"){ 93 | this.reportStatus(send, done, msg); 94 | } else { 95 | done("Invalid topic"); 96 | } 97 | }); 98 | 99 | this.on('close', () => { 100 | console.debug("Closed"); 101 | this.conf.unregisterCallback(this, this.device, callback); 102 | }); 103 | } 104 | } 105 | 106 | RED.nodes.registerType("smartthings-node-onoff", SmartthingsOnOffNode); 107 | 108 | }; 109 | -------------------------------------------------------------------------------- /smartthings/smartthings-openclose.html: -------------------------------------------------------------------------------- 1 | 79 | 80 | 100 | 101 | 133 | -------------------------------------------------------------------------------- /smartthings/smartthings-openclose.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsOpenCloseNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsOpenCloseNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | this.closeAsActive = config.closeAsActive; 17 | 18 | this.currentStatus = 0; 19 | 20 | this.reportStatus = function(send, done, original){ 21 | send = send || function() { node.send.apply(node,arguments) }; 22 | done = done || function() { }; 23 | let msg = { 24 | topic: "device", 25 | payload: { 26 | deviceId: this.device, 27 | deviceType: "contact", 28 | name: this.name, 29 | value: this.currentStatus, 30 | timestamp: new Date().toISOString() 31 | } 32 | }; 33 | 34 | if(original !== undefined){ 35 | original.payload = msg.payload; 36 | Object.assign(msg,original); 37 | } 38 | 39 | send(msg); 40 | done(); 41 | } 42 | 43 | this.updateStatus = function(currentStatus, send, done){ 44 | this.currentStatus = currentStatus; 45 | this.reportStatus(send, done); 46 | } 47 | 48 | this.pullStatus = function() { 49 | this.conf.getDeviceStatus(this.device,"main/capabilities/contactSensor").then( (status) => { 50 | console.debug("OpenCloseDevice("+this.name+") Status Refreshed"); 51 | console.debug(status); 52 | 53 | current = status["contact"]["value"]; 54 | if(current){ 55 | if(this.closeAsActive){ 56 | this.updateStatus((current.toLowerCase() == "closed" ? 1 : 0)); 57 | } else { 58 | this.updateStatus((current.toLowerCase() == "open" ? 1 : 0)); 59 | } 60 | } 61 | }).catch( err => { 62 | console.error("Ops... error getting device state (OpenCloseDevice)"); 63 | console.error(err); 64 | }); 65 | } 66 | 67 | if(this.conf && this.device){ 68 | const callback = (evt) => { 69 | console.debug("OpenCloseDevice("+this.name+") Callback called"); 70 | console.debug(evt); 71 | if(evt["attribute"] == "contact"){ 72 | if(this.closeAsActive){ 73 | this.updateStatus((evt["value"].toLowerCase() == "closed" ? 1 : 0)); 74 | } else { 75 | this.updateStatus((evt["value"].toLowerCase() == "open" ? 1 : 0)); 76 | } 77 | } 78 | } 79 | 80 | this.conf.registerCallback(this, this.device, callback); 81 | this.pullStatus(); 82 | 83 | this.on('input', (msg, send, done) => { 84 | send = send || function() { node.send.apply(node,arguments) }; 85 | done = done || function() { }; 86 | console.debug("Input Message Received"); 87 | console.log(msg); 88 | 89 | if(msg && msg.topic !== undefined){ 90 | switch(msg.topic){ 91 | case "pull": 92 | this.pullStatus(send, done, msg); 93 | break; 94 | 95 | case "update": 96 | this.reportStatus(send, done, msg); 97 | break; 98 | 99 | default: 100 | done("Invalid topic"); 101 | break; 102 | } 103 | } else { 104 | done("Invalid Message"); 105 | } 106 | }); 107 | 108 | this.on('close', () => { 109 | console.debug("Closed"); 110 | this.conf.unregisterCallback(this, this.device, callback); 111 | }); 112 | } 113 | } 114 | 115 | RED.nodes.registerType("smartthings-node-openclose", SmartthingsOpenCloseNode); 116 | }; 117 | -------------------------------------------------------------------------------- /smartthings/smartthings-power-meter.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-power-meter.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsPowerMeterNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsPowerMeterNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0, 19 | unit: "", 20 | }; 21 | 22 | this.reportState = function(send, done, original) { 23 | send = send || function() { node.send.apply(node,arguments) }; 24 | done = done || function() { }; 25 | let msg = { 26 | topic: "device", 27 | payload: { 28 | deviceId: this.device, 29 | deviceType: "power", 30 | name: this.name, 31 | value: this.state.value, 32 | unit: this.state.unit, 33 | timestamp: new Date().toISOString() 34 | } 35 | }; 36 | 37 | if(original !== undefined){ 38 | original.payload = msg.payload; 39 | Object.assign(msg,original); 40 | } 41 | 42 | send(msg); 43 | done(); 44 | } 45 | 46 | this.setState = function(value, send, done){ 47 | Object.assign(this.state, value); 48 | this.reportState(send, done); 49 | }; 50 | 51 | this.pullState = function(){ 52 | this.conf.getDeviceStatus(this.device,"main/capabilities/powerMeter").then( (status) => { 53 | console.debug("PowerMeterDevice("+this.name+") Status Refreshed"); 54 | console.debug(status); 55 | 56 | this.setState({ 57 | value: parseFloat(status["power"]["value"]), 58 | unit: status["power"]["unit"] 59 | }); 60 | 61 | }).catch( err => { 62 | console.error("Ops... error getting device state (PowerMeterDevice)"); 63 | console.error(err); 64 | }); 65 | }; 66 | 67 | if(this.conf && this.device){ 68 | const callback = (evt) => { 69 | console.debug("PowerMeterDevice("+this.name+") Callback called"); 70 | console.debug(evt); 71 | if(evt["attribute"] == "power"){ 72 | this.setState({ 73 | value: parseFloat(evt["value"]) 74 | }); 75 | } 76 | } 77 | 78 | this.conf.registerCallback(this, this.device, callback); 79 | this.pullState(); 80 | 81 | this.on('input', (msg, send, done) => { 82 | send = send || function() { node.send.apply(node,arguments) }; 83 | done = done || function() { }; 84 | console.debug("Input Message Received"); 85 | console.log(msg); 86 | 87 | if(msg && msg.topic !== undefined){ 88 | switch(msg.topic){ 89 | case "pull": 90 | this.pullState(); 91 | break; 92 | 93 | case "update": 94 | this.reportState(send, done, msg); 95 | break; 96 | 97 | default: 98 | done("Invalid Topic"); 99 | break; 100 | } 101 | } else { 102 | done("Invalid Message"); 103 | } 104 | }); 105 | 106 | this.on('close', () => { 107 | console.debug("Closed"); 108 | this.conf.unregisterCallback(this, this.device, callback); 109 | }); 110 | } 111 | } 112 | 113 | RED.nodes.registerType("smartthings-node-power-meter", SmartthingsPowerMeterNode); 114 | }; 115 | -------------------------------------------------------------------------------- /smartthings/smartthings-presence.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-presence.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsPresenceNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsPresenceNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.currentStatus = 0; 18 | 19 | this.reportStatus = function(send, done, original){ 20 | send = send || function() { node.send.apply(node,arguments) }; 21 | done = done || function() { }; 22 | let msg = { 23 | topic: "device", 24 | payload: { 25 | deviceId: this.device, 26 | deviceType: "presence", 27 | name: this.name, 28 | value: this.currentStatus, 29 | timestamp: new Date().toISOString() 30 | } 31 | }; 32 | 33 | if(original !== undefined){ 34 | original.payload = msg.payload; 35 | Object.assign(msg,original); 36 | } 37 | 38 | send(msg); 39 | done(); 40 | } 41 | 42 | this.updateStatus = function(currentStatus, send, done){ 43 | this.currentStatus = currentStatus; 44 | this.reportStatus(send, done); 45 | } 46 | 47 | this.pullStatus = function(){ 48 | this.conf.getDeviceStatus(this.device,"main/capabilities/presenceSensor").then( (status) => { 49 | console.debug("PresenceDevice("+this.name+") Status Refreshed"); 50 | console.debug(status); 51 | 52 | current = status["presence"]["value"]; 53 | if(current){ 54 | this.updateStatus((current.toLowerCase() == "present" ? 1 : 0)); 55 | } 56 | }).catch( err => { 57 | console.error("Ops... error getting device state (PresenceDevice)"); 58 | console.error(err); 59 | }); 60 | } 61 | 62 | if(this.conf && this.device){ 63 | const callback = (evt) => { 64 | console.debug("PresenceDevice("+this.name+") Callback called"); 65 | console.debug(evt); 66 | if(evt["attribute"] == "presence"){ 67 | this.updateStatus((evt["value"].toLowerCase() == "present" ? 1 : 0)); 68 | } 69 | } 70 | 71 | this.conf.registerCallback(this, this.device, callback); 72 | this.pullStatus(); 73 | 74 | this.on('input', (msg, send, done) => { 75 | send = send || function() { node.send.apply(node,arguments) }; 76 | done = done || function() { }; 77 | console.debug("Input Message Received"); 78 | console.log(msg); 79 | 80 | if(msg && msg.topic !== undefined){ 81 | switch(msg.topic){ 82 | case "pull": 83 | this.pullStatus(); 84 | break; 85 | 86 | case "update": 87 | this.reportStatus(send, done, msg); 88 | break; 89 | 90 | default: 91 | done("Invalid topic"); 92 | break; 93 | } 94 | } else { 95 | done("Invalid Message"); 96 | } 97 | }); 98 | 99 | this.on('close', () => { 100 | console.debug("Closed"); 101 | this.conf.unregisterCallback(this, this.device, callback); 102 | }); 103 | } 104 | } 105 | 106 | RED.nodes.registerType("smartthings-node-presence", SmartthingsPresenceNode); 107 | 108 | }; 109 | -------------------------------------------------------------------------------- /smartthings/smartthings-scene.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 108 | -------------------------------------------------------------------------------- /smartthings/smartthings-scene.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsSceneNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsSceneNode") 11 | 12 | this.conf = RED.nodes.getNode(config.conf); 13 | this.name = config.name; 14 | this.scene = config.scene; 15 | 16 | if(this.conf && this.scene){ 17 | 18 | this.on('input', (msg, send, done) => { 19 | send = send || function() { node.send.apply(node,arguments) }; 20 | done = done || function() { }; 21 | console.debug("Input Message Received"); 22 | if(msg && msg.topic === "scene"){ 23 | this.conf.executeScene(this.scene).then( (ret) => { 24 | done(); 25 | }).catch( (ret) => { 26 | this.error("Error executing scene"); 27 | done("Error executing scene"); 28 | }); 29 | } 30 | }); 31 | 32 | this.on('close', () => { 33 | console.debug("Closed"); 34 | }); 35 | } 36 | } 37 | 38 | RED.nodes.registerType("smartthings-node-scene", SmartthingsSceneNode); 39 | }; 40 | -------------------------------------------------------------------------------- /smartthings/smartthings-smoke.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-smoke.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsSmokeDetectorNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsSmokeDetectorNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0 19 | }; 20 | 21 | this.reportState = function(send, done, original) { 22 | send = send || function() { node.send.apply(node,arguments) }; 23 | done = done || function() { }; 24 | let msg = { 25 | topic: "device", 26 | payload: { 27 | deviceId: this.device, 28 | deviceType: "smoke", 29 | name: this.name, 30 | value: this.state.value, 31 | timestamp: new Date().toISOString() 32 | } 33 | }; 34 | 35 | if(original !== undefined){ 36 | original.payload = msg.payload; 37 | Object.assign(msg,original); 38 | } 39 | 40 | send(msg); 41 | done(); 42 | } 43 | 44 | this.setState = function(value, send, done){ 45 | Object.assign(this.state, value); 46 | this.reportState(send, done); 47 | }; 48 | 49 | this.pullState = function(value, send, done){ 50 | this.conf.getDeviceStatus(this.device,"main/capabilities/smokeDetector").then( (status) => { 51 | console.debug("SmokeDetectorDevice("+this.name+") Status Refreshed"); 52 | console.debug(status); 53 | 54 | this.setState({ 55 | value: (status["smoke"]["value"].toLowerCase() === "detected" ? 1 : 0), 56 | }); 57 | 58 | }).catch( err => { 59 | console.error("Ops... error getting device state (SmokeDetectorDevice)"); 60 | console.error(err); 61 | }); 62 | }; 63 | 64 | if(this.conf && this.device){ 65 | const callback = (evt) => { 66 | console.debug("SmokeDetectorDevice("+this.name+") Callback called"); 67 | console.debug(evt); 68 | if(evt["attribute"] == "smoke"){ 69 | this.setState({ 70 | value: (evt["value"].toLowerCase() === "detected" ? 1 : 0) 71 | }); 72 | } 73 | } 74 | 75 | this.conf.registerCallback(this, this.device, callback); 76 | this.pullState(); 77 | 78 | this.on('input', (msg, send, done) => { 79 | send = send || function() { node.send.apply(node,arguments) }; 80 | done = done || function() { }; 81 | console.debug("Input Message Received"); 82 | console.log(msg); 83 | 84 | if(msg && msg.topic !== undefined){ 85 | switch(msg.topic){ 86 | case "pull": 87 | this.pullState(); 88 | break; 89 | 90 | case "update": 91 | this.reportState(send, done, msg); 92 | break; 93 | 94 | default: 95 | done("Invalid topic"); 96 | break; 97 | } 98 | } else { 99 | done("Invalid message"); 100 | } 101 | }); 102 | 103 | this.on('close', () => { 104 | console.debug("Closed"); 105 | this.conf.unregisterCallback(this, this.device, callback); 106 | }); 107 | } 108 | } 109 | 110 | RED.nodes.registerType("smartthings-node-smoke-detector", SmartthingsSmokeDetectorNode); 111 | }; 112 | -------------------------------------------------------------------------------- /smartthings/smartthings-status.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 130 | -------------------------------------------------------------------------------- /smartthings/smartthings-status.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsStatusNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsStatusNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.currentStatus = 0; 18 | 19 | this.reportStatus = function(send, done, original){ 20 | send = send || function() { node.send.apply(node,arguments) }; 21 | done = done || function() { }; 22 | let msg = { 23 | topic: "device", 24 | payload: { 25 | deviceId: this.device, 26 | name: this.name, 27 | status: this.currentStatus, 28 | timestamp: new Date().toISOString() 29 | } 30 | }; 31 | 32 | if(original !== undefined){ 33 | original.payload = msg.payload; 34 | Object.assign(msg,original); 35 | } 36 | 37 | send(msg); 38 | done(); 39 | } 40 | 41 | this.updateStatus = function(currentStatus, send, done){ 42 | this.currentStatus = currentStatus; 43 | this.reportStatus(send, done); 44 | } 45 | 46 | this.pullStatus = function(){ 47 | this.conf.getDeviceStatus(this.device).then( (status) => { 48 | console.debug("StatusDevice("+this.name+") Status Refreshed"); 49 | console.debug(status); 50 | 51 | this.updateStatus(status); 52 | }).catch( err => { 53 | console.error("Ops... error getting device state (StatusDevice)"); 54 | console.error(err); 55 | }); 56 | } 57 | 58 | if(this.conf && this.device){ 59 | const callback = (evt) => { 60 | console.debug("StatusDevice("+this.name+") Callback called"); 61 | console.debug(evt); 62 | if(evt){ 63 | this.pullStatus(); 64 | } 65 | } 66 | 67 | this.conf.registerCallback(this, this.device, callback); 68 | this.pullStatus(); 69 | 70 | this.on('input', (msg, send, done) => { 71 | send = send || function() { node.send.apply(node,arguments) }; 72 | done = done || function() { }; 73 | console.debug("Input Message Received"); 74 | console.log(msg); 75 | 76 | if(msg && msg.topic !== undefined){ 77 | switch(msg.topic){ 78 | case "pull": 79 | this.pullStatus(); 80 | break; 81 | 82 | case "update": 83 | this.reportStatus(send, done, msg); 84 | break; 85 | 86 | default: 87 | done("Invalid topic"); 88 | break; 89 | } 90 | } else { 91 | done("Invalid Message"); 92 | } 93 | }); 94 | 95 | this.on('close', () => { 96 | console.debug("Closed"); 97 | this.conf.unregisterCallback(this, this.device, callback); 98 | }); 99 | } 100 | } 101 | 102 | RED.nodes.registerType("smartthings-node-status", SmartthingsStatusNode); 103 | }; 104 | -------------------------------------------------------------------------------- /smartthings/smartthings-temperature.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-temperature.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsTemperatureNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsTemperatureNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0, 19 | unit: "", 20 | }; 21 | 22 | this.reportState = function(send, done, original){ 23 | send = send || function() { node.send.apply(node,arguments) }; 24 | done = done || function() { }; 25 | let msg = { 26 | topic: "device", 27 | payload: { 28 | deviceId: this.device, 29 | deviceType: "temperature", 30 | name: this.name, 31 | value: this.state.value, 32 | unit: this.state.unit, 33 | timestamp: new Date().toISOString() 34 | } 35 | }; 36 | 37 | if(original !== undefined){ 38 | original.payload = msg.payload; 39 | Object.assign(msg,original); 40 | } 41 | 42 | send(msg); 43 | done(); 44 | } 45 | 46 | this.setState = function(value, send, done){ 47 | Object.assign(this.state, value); 48 | this.reportState(send, done); 49 | }; 50 | 51 | this.pullState = function(){ 52 | this.conf.getDeviceStatus(this.device,"main/capabilities/temperatureMeasurement").then( (status) => { 53 | console.debug("TemperatureDevice("+this.name+") Status Refreshed"); 54 | console.debug(status); 55 | 56 | this.setState({ 57 | value: parseFloat(status["temperature"]["value"]), 58 | unit: status["temperature"]["unit"] 59 | }); 60 | 61 | }).catch( err => { 62 | console.error("Ops... error getting device state (TemperatureDevice)"); 63 | console.error(err); 64 | }); 65 | }; 66 | 67 | if(this.conf && this.device){ 68 | const callback = (evt) => { 69 | console.debug("TemperatureDevice("+this.name+") Callback called"); 70 | console.debug(evt); 71 | if(evt["attribute"] == "temperature"){ 72 | this.setState({ 73 | value: parseFloat(evt["value"]) 74 | }); 75 | } 76 | } 77 | 78 | this.conf.registerCallback(this, this.device, callback); 79 | this.pullState(); 80 | 81 | this.on('input', (msg, send, done) => { 82 | send = send || function() { node.send.apply(node,arguments) }; 83 | done = done || function() { }; 84 | console.debug("Input Message Received"); 85 | console.log(msg); 86 | 87 | if(msg && msg.topic !== undefined){ 88 | switch(msg.topic){ 89 | case "pull": 90 | this.pullState(); 91 | break; 92 | 93 | case "update": 94 | this.reportState(send, done, msg); 95 | break; 96 | 97 | default: 98 | done("Invalid topic"); 99 | break; 100 | } 101 | } else { 102 | done("Invalid message"); 103 | } 104 | }); 105 | 106 | this.on('close', () => { 107 | console.debug("Closed"); 108 | this.conf.unregisterCallback(this, this.device, callback); 109 | }); 110 | } 111 | } 112 | 113 | RED.nodes.registerType("smartthings-node-temperature", SmartthingsTemperatureNode); 114 | }; 115 | -------------------------------------------------------------------------------- /smartthings/smartthings-threeaxis.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-threeaxis.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsThreeAxisNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsThreeAxisNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: { 19 | x: 0, 20 | y: 0, 21 | z: 0, 22 | } 23 | }; 24 | 25 | this.reportState = function(send, done, original) { 26 | send = send || function() { node.send.apply(node,arguments) }; 27 | done = done || function() { }; 28 | let msg = { 29 | topic: "device", 30 | payload: { 31 | deviceId: this.device, 32 | deviceType: "threeAxis", 33 | name: this.name, 34 | value: this.state.value, 35 | timestamp: new Date().toISOString() 36 | } 37 | }; 38 | 39 | if(original !== undefined){ 40 | original.payload = msg.payload; 41 | Object.assign(msg,original); 42 | } 43 | 44 | send(msg); 45 | done(); 46 | } 47 | 48 | this.setState = function(value, send, done){ 49 | Object.assign(this.state, value); 50 | this.reportState(send, done); 51 | }; 52 | 53 | this.pullState = function(value, send, done){ 54 | this.conf.getDeviceStatus(this.device,"main/capabilities/threeAxis").then( (status) => { 55 | console.debug("ThreeAxisDevice("+this.name+") Status Refreshed"); 56 | console.debug(status); 57 | 58 | this.setState({ 59 | value: { 60 | x: status["threeAxis"]["value"][0], 61 | y: status["threeAxis"]["value"][1], 62 | z: status["threeAxis"]["value"][2], 63 | } 64 | }); 65 | 66 | }).catch( err => { 67 | console.error("Ops... error getting device state (ThreeAxisDevice)"); 68 | console.error(err); 69 | }); 70 | }; 71 | 72 | if(this.conf && this.device){ 73 | const callback = (evt) => { 74 | console.debug("ThreeAxisDevice("+this.name+") Callback called"); 75 | console.debug(evt); 76 | if(evt["attribute"] == "threeAxis"){ 77 | this.setState({ 78 | value: { 79 | x: evt["value"][0], 80 | y: evt["value"][1], 81 | z: evt["value"][2], 82 | } 83 | }); 84 | } 85 | } 86 | 87 | this.conf.registerCallback(this, this.device, callback); 88 | this.pullState(); 89 | 90 | this.on('input', (msg, send, done) => { 91 | send = send || function() { node.send.apply(node,arguments) }; 92 | done = done || function() { }; 93 | console.debug("Input Message Received"); 94 | console.log(msg); 95 | 96 | if(msg && msg.topic !== undefined){ 97 | switch(msg.topic){ 98 | case "pull": 99 | this.pullState(); 100 | break; 101 | 102 | case "update": 103 | this.reportState(send, done, msg); 104 | break; 105 | 106 | default: 107 | done("Invalid topic"); 108 | break; 109 | } 110 | } else { 111 | done("Invalid message"); 112 | } 113 | }); 114 | 115 | this.on('close', () => { 116 | console.debug("Closed"); 117 | this.conf.unregisterCallback(this, this.device, callback); 118 | }); 119 | } 120 | } 121 | 122 | RED.nodes.registerType("smartthings-node-three-axis", SmartthingsThreeAxisNode); 123 | }; 124 | -------------------------------------------------------------------------------- /smartthings/smartthings-water.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 95 | 96 | 128 | -------------------------------------------------------------------------------- /smartthings/smartthings-water.js: -------------------------------------------------------------------------------- 1 | var Promise = require('promise'); 2 | 3 | module.exports = function(RED) { 4 | 5 | function SmartthingsWaterNode(config) { 6 | RED.nodes.createNode(this, config); 7 | 8 | let node = this; 9 | 10 | console.debug("SmartthingsWaterNode") 11 | console.debug(config); 12 | 13 | this.conf = RED.nodes.getNode(config.conf); 14 | this.name = config.name; 15 | this.device = config.device; 16 | 17 | this.state = { 18 | value: 0 19 | }; 20 | 21 | this.reportState = function(send, done, original) { 22 | send = send || function() { node.send.apply(node,arguments) }; 23 | done = done || function() { }; 24 | let msg = { 25 | topic: "device", 26 | payload: { 27 | deviceId: this.device, 28 | deviceType: "water", 29 | name: this.name, 30 | value: this.state.value, 31 | timestamp: new Date().toISOString() 32 | } 33 | }; 34 | 35 | if(original !== undefined){ 36 | original.payload = msg.payload; 37 | Object.assign(msg,original); 38 | } 39 | 40 | send(msg); 41 | done(); 42 | } 43 | 44 | this.setState = function(value, send, done){ 45 | Object.assign(this.state, value); 46 | this.reportState(send, done); 47 | }; 48 | 49 | this.pullState = function(value, send, done){ 50 | this.conf.getDeviceStatus(this.device,"main/capabilities/waterSensor").then( (status) => { 51 | console.debug("WaterDevice("+this.name+") Status Refreshed"); 52 | console.debug(status); 53 | 54 | this.setState({ 55 | value: (status["water"]["value"].toLowerCase() === "wet" ? 1 : 0), 56 | }); 57 | 58 | }).catch( err => { 59 | console.error("Ops... error getting device state (WaterDevice)"); 60 | console.error(err); 61 | }); 62 | }; 63 | 64 | if(this.conf && this.device){ 65 | const callback = (evt) => { 66 | console.debug("WaterDevice("+this.name+") Callback called"); 67 | console.debug(evt); 68 | if(evt["attribute"] == "water"){ 69 | this.setState({ 70 | value:(evt["value"].toLowerCase() === "wet" ? 1 : 0) 71 | }); 72 | } 73 | } 74 | 75 | this.conf.registerCallback(this, this.device, callback); 76 | this.pullState(); 77 | 78 | this.on('input', (msg, send, done) => { 79 | send = send || function() { node.send.apply(node,arguments) }; 80 | done = done || function() { }; 81 | console.debug("Input Message Received"); 82 | console.log(msg); 83 | 84 | if(msg && msg.topic !== undefined){ 85 | switch(msg.topic){ 86 | case "pull": 87 | this.pullState(); 88 | break; 89 | 90 | case "update": 91 | this.reportState(send, done, msg); 92 | break; 93 | 94 | default: 95 | done("Invalid topic"); 96 | break; 97 | } 98 | } else { 99 | done("Invalid message"); 100 | } 101 | }); 102 | 103 | this.on('close', () => { 104 | console.debug("Closed"); 105 | this.conf.unregisterCallback(this, this.device, callback); 106 | }); 107 | } 108 | } 109 | 110 | RED.nodes.registerType("smartthings-node-water", SmartthingsWaterNode); 111 | }; 112 | --------------------------------------------------------------------------------