13 | | Display Name | 14 |Type | 15 |API | 16 |
---|---|---|---|
20 | | {{name}} | 21 |{{type}} | 22 |{{api}} | 23 |
├── .gitignore
├── .vscode
├── formatter.json
└── launch.json
├── LICENSE
├── README.md
├── app
├── api
│ ├── cameras.js
│ ├── dashboards.js
│ ├── importexport.js
│ ├── index.js
│ ├── settings.js
│ ├── smartthings.js
│ ├── styles.js
│ ├── templates.js
│ └── weather.js
├── controllers
│ ├── cameras.js
│ ├── dashboards.js
│ ├── device.js
│ ├── home.js
│ ├── importexport.js
│ ├── index.js
│ ├── settings.js
│ ├── smartthings.js
│ ├── styles.js
│ ├── templates.js
│ └── updates.js
├── index.js
└── views
│ ├── cameras.hbs
│ ├── dashboard-device.hbs
│ ├── dashboard-edit.hbs
│ ├── dashboard.hbs
│ ├── dashboards.hbs
│ ├── home.hbs
│ ├── importexport.hbs
│ ├── layouts
│ └── main.hbs
│ ├── settings.hbs
│ ├── smartthings.hbs
│ ├── styles.hbs
│ └── templates.hbs
├── index.js
├── install.js
├── package.json
├── public
├── css
│ ├── codemirror.css
│ ├── metro-colors.css
│ ├── metro-colors.min.css
│ ├── metro-icons.css
│ ├── metro-icons.min.css
│ ├── metro-responsive.css
│ ├── metro-responsive.min.css
│ ├── metro-rtl.css
│ ├── metro-rtl.min.css
│ ├── metro-schemes.css
│ ├── metro-schemes.min.css
│ ├── metro.css
│ └── metro.min.css
├── fonts
│ ├── metro.eot
│ ├── metro.svg
│ ├── metro.ttf
│ ├── metro.woff
│ └── selection.json
└── js
│ ├── FileSaver.min.js
│ ├── codemirror.js
│ ├── dashboard-device-edit.js
│ ├── dashboard-edit.js
│ ├── dashboard.js
│ ├── dashboards.js
│ ├── dateTime.js
│ ├── global.js
│ ├── importexport.js
│ ├── metro.js
│ ├── metro.min.js
│ ├── settings.js
│ ├── smartthings.js
│ ├── styles.js
│ ├── templates.js
│ ├── updates.js
│ └── weather.js
└── upgrade.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directories
27 | node_modules
28 | jspm_packages
29 | data/*
30 |
31 | # Optional npm cache directory
32 | .npm
33 |
34 | # Optional REPL history
35 | .node_repl_history
36 |
37 | *.seed
38 | *.log
39 | *.csv
40 | *.dat
41 | *.out
42 | *.pid
43 | *.gz
44 | *.sublime-project
45 | *.sublime-workspace
46 | .idea
47 | .DS_Store
48 |
49 | node_modules
50 | private/certs
51 |
52 | docker-compose.*.yml
53 | settings.*.json
54 |
55 | data
--------------------------------------------------------------------------------
/.vscode/formatter.json:
--------------------------------------------------------------------------------
1 | {
2 | "onSave": true,
3 | "javascript": {
4 | "indent_size": 4,
5 | "indent_char": " ",
6 | "eol": "auto",
7 | "preserve_newlines": true,
8 | "break_chained_methods": false,
9 | "max_preserve_newlines": 0,
10 | "space_in_paren": false,
11 | "space_in_empty_paren": false,
12 | "jslint_happy": false,
13 | "space_after_anon_function": false,
14 | "keep_array_indentation": true,
15 | "space_before_conditional": true,
16 | "unescape_strings": false,
17 | "wrap_line_length": 0,
18 | "e4x": false,
19 | "end_with_newline": false,
20 | "comma_first": false,
21 | "brace_style": "collapse-preserve-inline"
22 | },
23 | "css": {
24 | "indent_size": 4,
25 | "indentCharacter": " ",
26 | "indent_char": " ",
27 | "selector_separator_newline": true,
28 | "end_with_newline": false,
29 | "newline_between_rules": true,
30 | "eol": "\n"
31 | },
32 | "html": {
33 | "indent_inner_html": true,
34 | "indent_size": 4,
35 | "indent_char": " ",
36 | "indent_character": " "
37 | }
38 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible Node.js debug attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "program": "${workspaceRoot}\\index.js",
12 | "cwd": "${workspaceRoot}"
13 | },
14 | {
15 | "type": "node",
16 | "request": "launch",
17 | "name": "Launch Upgrade Program",
18 | "program": "${workspaceRoot}\\upgrade.js",
19 | "cwd": "${workspaceRoot}"
20 | },
21 | {
22 | "type": "node",
23 | "request": "attach",
24 | "name": "Attach to Process",
25 | "port": 5858
26 | }
27 | ]
28 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # open-dash-diy
2 | Open-Dash Node.js core
3 |
4 | Open-Dash Node.js Install Instructions
5 |
6 | Prerequisites:
7 | -Install Git (or download git zip file and expand)
8 | -Install Node.js https://nodejs.org/en/download/
9 | -Install the Open-Dash SmartApp API and remember to enable oauth, get TOKEN and API URL
10 |
11 | If Installing on a Raspberry Pi 2/3
12 | Raspberry Pi / Rasbian ships with an old version of node.
13 | sudo su
14 | apt-get update
15 | apt-get upgrade
16 |
17 | apt-get remove node
18 |
19 | curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
20 | sudo apt-get install -y nodejs
21 |
22 | apt-get autoremove
23 |
24 | Create Folder on OS you want to run from
25 |
26 | Command Line / Terminal
27 | "git clone https://github.com/open-dash/open-dash-diy.git"
28 |
29 | change into folder "open-dash-diy"
30 |
31 | Install node_modules via npm for Open-Dash
32 | run "npm install"
33 |
34 | Create Data Folder and JSON Files for Project
35 | run "node install.js"
36 |
37 | If upgrading, run "node upgrade.js"
38 | Run Open-Dash
39 | "node index.js"
40 |
41 | Open Browser to "http://localhost:3000"
42 |
43 | Go To Settings
44 |
45 | Insert your Client ID and Client Secret from the SmartApp Install Process
46 |
47 | Click Save
48 |
49 | Connect with SmartThings and authorize devices.
50 |
51 | After completing the oauth2 process, you should see weather start to populate upper right near menu. If so, you are connected to SmartThings Open-Dash API SmartApp
52 |
53 | Go To Menu -> SmartThings
54 |
55 | Click "Get Devices From SmartThings"
56 |
57 | After a few seconds, should populate the table with all your subscribed to devices
58 |
59 | Click "Save Devices" to save them to the local JSON file
60 |
61 | Repeat for each tab.
62 |
63 | Go to Menu -> Dashboards
64 |
65 | Create new dashboard
66 |
67 | Type in a Name and Click Add
68 |
69 | Click on Newly created dashboard
70 |
71 | Click "edit" next to Dashboard Name in Header
72 |
73 | Select devices to add to Dashboard
74 |
75 | Click add Devices
76 |
77 | click Edit next to a device to change the template, order, name or enable/disable it
78 |
79 | View Dashboard by clicking the dashboard name next to "edit"
80 |
81 | All devices right now come in with the default template that just shows all attributes and their values. Go back into the edit screen and edit each device to pick the right template for the type of device.
82 |
83 | From there you can edit Styles and Templates or import/export them.
84 |
85 | Customize to your delight and enjoy!
86 |
87 | Submit bugs, issues and feature requests on the github repo "Issues" area.
88 |
--------------------------------------------------------------------------------
/app/api/cameras.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | const app = express();
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | var settings = new SelfReloadJSON(appRoot + '/data/settings.json');
8 | var cameras = new SelfReloadJSON(appRoot + '/data/cameras.json');
9 |
10 | module.exports.set = function(app) {
11 |
12 | app.get('/api/camera/:id', (request, response) => {
13 | getImage(request.params.id, function(err, result) {
14 | //response.send('');
15 | response.setHeader('Content-Type', 'image/jpeg');
16 | response.end(result, 'binary');
17 | });
18 |
19 | });
20 | };
21 |
22 | var getImage = function(id, callback) {
23 | var request2 = require('request').defaults({ encoding: null });
24 | var camera = {};
25 | cameras.cameras.forEach((cam) => { camera = cam; });
26 |
27 | request2.get(camera.url, function(error, response, body) {
28 | if (!error && response.statusCode == 200) {
29 | data = "data:image/jpeg;base64," + new Buffer(body).toString('base64');
30 | //console.log(data);
31 | callback(null, body);
32 | }
33 | });
34 | };
--------------------------------------------------------------------------------
/app/api/dashboards.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | var uuid = require('uuid');
5 | const fs = require('fs');
6 | const app = express();
7 | var SelfReloadJSON = require('self-reload-json');
8 | const appRoot = require('app-root-path');
9 | var dashboards = new SelfReloadJSON(appRoot + '/data/dashboards.json');
10 | var smartthings = new SelfReloadJSON(appRoot + '/data/smartthings.json');
11 | var cameras = new SelfReloadJSON(appRoot + '/data/cameras.json');
12 | var updates = new SelfReloadJSON(appRoot + '/data/updates.json');
13 | var templates = new SelfReloadJSON(appRoot + '/data/templates.json');
14 |
15 | module.exports.set = function(app) {
16 |
17 | app.post('/api/dashboard/:id/:cmd', (request, response) => {
18 | response.setHeader('Content-Type', 'application/json');
19 | if (request.params.cmd == "save") {
20 | saveDashboard(request.params.id, request.body, function(err, result) {
21 | if (err) {
22 | response.send(500, { error: 'something went wrong' });
23 | } else {
24 | response.send(result);
25 | }
26 | });
27 | } else {
28 | updateDashboard(request.params.cmd, request.params.id, request.body, function(err, result) {
29 | if (err) {
30 | response.send(500, { error: 'something went wrong' });
31 | } else {
32 | response.send(result);
33 | }
34 | });
35 | };
36 | });
37 |
38 | app.post('/api/dashboard/add', (request, response) => {
39 | response.setHeader('Content-Type', 'application/json');
40 | addDashboard(request.body, function(err, result) {
41 | if (err) {
42 | response.send(500, { error: 'something went wrong' });
43 | } else {
44 | response.send(result);
45 | }
46 | });
47 | });
48 |
49 | app.get('/api/dashboard/:dashid/device/:deviceid', (request, response) => {
50 | response.setHeader('Content-Type', 'application/json');
51 | findDashDevice(request.params.dashid, request.params.deviceid, function(err, result) {
52 | if (err) {
53 | response.send(500, { error: 'something went wrong' });
54 | } else {
55 | response.send(result);
56 | }
57 | });
58 | });
59 |
60 | app.post('/api/dashboard/:dashid/device/:deviceid/save', (request, response) => {
61 | response.setHeader('Content-Type', 'application/json');
62 | saveDashDevice(request.params.dashid, request.params.deviceid, request.body, function(err, result) {
63 | if (err) {
64 | response.send(500, { error: 'something went wrong' });
65 | } else {
66 | response.send(result);
67 | }
68 | });
69 | });
70 |
71 | app.get('/api/dashboard/:dashid/devices', (request, response) => {
72 | response.setHeader('Content-Type', 'application/json');
73 | findDevices(request.params.dashid, function(err, result) {
74 | if (err) {
75 | response.send(500, { error: 'something went wrong' });
76 | } else {
77 | response.send(result);
78 | }
79 | });
80 | });
81 |
82 | };
83 |
84 | var findDashDevice = function(dashId, deviceId, callback) {
85 | var dashboard = {};
86 | for (i = 0; dashboards.dashboards.length > i; i++) {
87 | if (dashboards.dashboards[i].id == dashId) {
88 | dashboard = dashboards.dashboards[i];
89 | }
90 | }
91 | var device = {};
92 | for (i = 0; dashboard.devices.length > i; i++) {
93 | if (dashboard.devices[i].dashDevId == deviceId) {
94 | device = dashboard.devices[i];
95 | }
96 | }
97 | callback(null, device);
98 | };
99 |
100 | var saveDashDevice = function(dashId, deviceId, data, callback) {
101 | var dashboard = {};
102 | for (i = 0; dashboards.dashboards.length > i; i++) {
103 | if (dashboards.dashboards[i].id == dashId) {
104 | dashboard = dashboards.dashboards[i];
105 | }
106 | }
107 | var device = {};
108 | for (i = 0; dashboard.devices.length > i; i++) {
109 | if (dashboard.devices[i].dashDevId == deviceId) {
110 | device = dashboard.devices[i];
111 | }
112 | }
113 | device.name = data.name;
114 | device.enabled = data.enabled;
115 | device.template = data.template;
116 | device.order = data.order;
117 | dashboards.save();
118 | callback(null, device);
119 | };
120 |
121 | var findDevices = function(dashId, callback) {
122 | var dashboard = {};
123 | for (i = 0; dashboards.dashboards.length > i; i++) {
124 | if (dashboards.dashboards[i].id == dashId) {
125 | dashboard = dashboards.dashboards[i];
126 | }
127 | }
128 | var devices = [];
129 | for (i = 0; dashboard.devices.length > i; i++) {
130 | if (dashboard.devices[i].enabled) {
131 | devices.push({
132 | "id": dashboard.devices[i].dashDevId,
133 | "order": dashboard.devices[i].order
134 | })
135 | };
136 | }
137 |
138 | callback(null, devices);
139 | };
140 |
141 | var updateDashboard = function(cmd, id, data, callback) {
142 | var dashboard = {};
143 | for (i = 0; dashboards.dashboards.length > i; i++) {
144 | if (dashboards.dashboards[i].id == id) {
145 | dashboard = dashboards.dashboards[i];
146 | }
147 | }
148 | switch (cmd) {
149 | case "add":
150 | //var dashIds = dashboard.devices.map(e => e.id);
151 | if (data.type == "blank") {
152 | var dashDevice = {};
153 | dashDevice.name = "Blank Tile";
154 | dashDevice.type = "Blank"
155 | dashDevice.id = "Blank_" + uuid.v1();
156 | dashDevice.template = "Blank";
157 | dashDevice.enabled = true;
158 | dashDevice.order = "1";
159 | dashDevice.dashDevId = uuid.v1();
160 | dashboard.devices.push(dashDevice);
161 | } else {
162 | for (var x in data) {
163 | var match = false;
164 | //check if already in list, remove if you want duplicate devices
165 | //for (var d in dashIds) {
166 | // if (dashIds[d] == data[x].id) { match = true }
167 | //}
168 | //if (match) {
169 | //console.log('already exists');
170 | //} else {
171 | var device = {};
172 | var temps = templates.templates.map(e => e.id);
173 | //loop through smartthings devices
174 | if (data[x].type != "Routine") {
175 | for (i = 0; smartthings.devices.length > i; i++) {
176 | if (smartthings.devices[i].id == data[x].id) {
177 | var dashDevice = smartthings.devices[i];
178 | if (temps.indexOf(dashDevice.type) >= 0) {
179 | dashDevice.template = dashDevice.type
180 | } else {
181 | for (var f in temps) {
182 | var xx = temps[f];
183 | if (dashDevice.type.toLowerCase().includes(temps[f].toLowerCase())) {
184 | dashDevice.template = temps[f];
185 | }
186 | }
187 | if (dashDevice.template == null) { dashDevice.template = "default" }
188 | }
189 | dashDevice.enabled = true;
190 | dashDevice.order = "99";
191 | dashDevice.dashDevId = uuid.v1();
192 | dashboard.devices.push(dashDevice);
193 | }
194 | }
195 | } else {
196 | for (i = 0; smartthings.routines.length > i; i++) {
197 | if (smartthings.routines[i].id == data[x].id) {
198 | var dashDevice = smartthings.routines[i];
199 | dashDevice.template = "routine";
200 | dashDevice.enabled = true
201 | dashDevice.order = "99"
202 | dashDevice.api = "smartthings";
203 | dashDevice.name = smartthings.routines[i].label;
204 | dashDevice.commands = [{ command: "toggle" }];
205 | dashDevice.type = "Routine";
206 | dashDevice.dashDevId = uuid.v1();
207 | dashboard.devices.push(dashDevice);
208 | }
209 | }
210 | }
211 | //}
212 | }
213 | }
214 | break;
215 |
216 | case "addcamera":
217 |
218 | for (i = 0; cameras.cameras.length > i; i++) {
219 | if (cameras.cameras[i].id == data[x]) {
220 | var dashDevice = cameras.cameras[i];
221 | dashDevice.template = "camera";
222 | dashDevice.enabled = true;
223 | dashDevice.order = "0";
224 | dashDevice.path = "/api/camera/" + dashDevice.id;
225 | dashDevice.dashDevId = uuid.v1();
226 | dashboard.devices.push(dashDevice);
227 | }
228 | }
229 | break;
230 | case "remove":
231 | var devicesDelete = [];
232 | for (var deviceId in data) {
233 | try {
234 | for (i = 0; dashboard.devices.length > i; i++) {
235 | if (dashboard.devices[i].dashDevId == data[deviceId]) {
236 | dashboard.devices.splice([i], 1);
237 | }
238 | }
239 | } catch (err) {
240 | console.log(err);
241 | }
242 | }
243 |
244 | break;
245 | default:
246 | break;
247 | }
248 | dashboards.save();
249 |
250 | //save dashboards
251 | callback(null, "success");
252 | };
253 |
254 | var addDashboard = function(data, callback) {
255 | var dashboard = {};
256 | dashboard.id = getId();
257 | dashboard.name = data.name;
258 | dashboard.css = "none";
259 | dashboard.devices = [];
260 | dashboards.dashboards.push(dashboard);
261 | dashboards.save();
262 | callback(null, "success");
263 | };
264 |
265 | var saveDashboard = function(id, body, callback) {
266 | var dashboard = {};
267 | for (i = 0; dashboards.dashboards.length > i; i++) {
268 | if (dashboards.dashboards[i].id == id) {
269 | dashboard = dashboards.dashboards[i];
270 | }
271 | }
272 | dashboard.name = body.name
273 | dashboard.css = body.css
274 | dashboards.save();
275 | callback(null, "success");
276 | };
277 |
278 |
279 | var getId = function() {
280 | var id = 0;
281 | for (var dash in dashboards.dashboards) {
282 | if (parseInt(dash) <= id) {
283 | id++;
284 | }
285 | }
286 | return id.toString();
287 | };
--------------------------------------------------------------------------------
/app/api/importexport.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | var multer = require('multer')
5 | var storage = multer.memoryStorage()
6 | var upload = multer({ storage: storage })
7 | const app = express();
8 | var SelfReloadJSON = require('self-reload-json');
9 | const appRoot = require('app-root-path');
10 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
11 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
12 | var templates = new SelfReloadJSON(appRoot + '/data/templates.json');
13 |
14 | module.exports.set = function(app) {
15 | app.use(bodyParser.json());
16 |
17 | app.post('/api/importexport/export', (request, response) => {
18 | response.setHeader('Content-Type', 'application/json');
19 | var exported = request.body;
20 |
21 | var exportStyles = [];
22 | request.body.styles.forEach((id) => {
23 |
24 | getStyle(id, function(err, result) {
25 | exportStyles.push(result);
26 | });
27 | });
28 |
29 | var exportTemplates = [];
30 | request.body.templates.forEach((id) => {
31 |
32 | getTemplate(id, function(err, result) {
33 | exportTemplates.push(result);
34 | });
35 | });
36 | var fullExport = {};
37 | fullExport.styles = exportStyles;
38 | fullExport.templates = exportTemplates;
39 |
40 | response.send(JSON.stringify(fullExport));
41 | });
42 |
43 | app.post('/importexport/upload', upload.single('upload-file'), (request, response, next) => {
44 | var importJson = request.file.buffer.toString();
45 | var toImport;
46 | if (importJson[0] != "{") {
47 | toImport = JSON.parse(importJson.slice(1));
48 | } else {
49 | toImport = JSON.parse(importJson);
50 | }
51 | //console.log(toImport);
52 |
53 | for (var i in toImport.styles) {
54 | if (toImport.styles[i].name.toLowerCase() == "global") {
55 | styles.styles.global = toImport.styles[i].css;
56 | } else {
57 | var match = false;
58 | for (var x in styles.styles.dashboards) {
59 | if (toImport.styles[i].name.toLowerCase() == styles.styles.dashboards[x].name.toLowerCase()) {
60 | styles.styles.dashboards[x].name = toImport.styles[i].name
61 | styles.styles.dashboards[x].css = toImport.styles[i].css
62 | match = true;
63 | }
64 | }
65 | if (!match) {
66 | var t = {};
67 | t.id = styles.styles.dashboards.length;
68 | t.css = toImport.styles[i].css;
69 | t.name = toImport.styles[i].name
70 | styles.styles.dashboards.push(t);
71 | }
72 | }
73 | }
74 | styles.save()
75 | for (var i in toImport.templates) {
76 | var match = false;
77 | for (var x in templates.templates) {
78 | if (toImport.templates[i].name.toLowerCase() == templates.templates[x].id.toLowerCase()) {
79 | templates.templates[x].id = toImport.templates[i].name
80 | templates.templates[x].content = toImport.templates[i].content
81 | match = true;
82 | }
83 | }
84 | if (!match) {
85 | var t = {};
86 | t.id = toImport.templates[i].name;
87 | t.content = toImport.templates[i].content
88 | templates.templates.push(t);
89 | }
90 | }
91 | templates.save()
92 | response.send("Imported");
93 | });
94 |
95 | }
96 |
97 | var getStyle = function(tempid, callback) {
98 | var style = {};
99 | if (tempid == "global") {
100 | style.name = "global";
101 | style.css = styles.styles.global
102 | } else {
103 | style.name = styles.styles.dashboards[tempid].name;
104 | style.css = styles.styles.dashboards[tempid].css;
105 | }
106 | callback(null, style)
107 | }
108 |
109 | var getTemplate = function(tempid, callback) {
110 | var template = {};
111 | for (var i in templates.templates) {
112 | if (templates.templates[i].id == tempid) {
113 | template.name = templates.templates[i].id;
114 | template.content = templates.templates[i].content;
115 | }
116 | }
117 | callback(null, template)
118 | }
--------------------------------------------------------------------------------
/app/api/index.js:
--------------------------------------------------------------------------------
1 | var smartthings = require('./smartthings');
2 | var dashboards = require('./dashboards');
3 | var weather = require('./weather');
4 | var settingsAPI = require('./settings');
5 | var cameras = require('./cameras');
6 | var templates = require('./templates');
7 | var styles = require('./styles');
8 | var importexport = require('./importexport');
9 |
10 | module.exports.set = function(app) {
11 | smartthings.set(app);
12 | dashboards.set(app);
13 | weather.set(app);
14 | settingsAPI.set(app);
15 | cameras.set(app);
16 | templates.set(app);
17 | styles.set(app);
18 | importexport.set(app);
19 | }
--------------------------------------------------------------------------------
/app/api/settings.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | const app = express();
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 |
9 | module.exports.set = function(app) {
10 | app.use(bodyParser.json());
11 |
12 | app.post('/api/settings/save', (request, response) => {
13 | response.setHeader('Content-Type', 'application/json');
14 | saveSettings(request.body, function(err, result) {
15 | if (err) {
16 | response.send(500, { error: 'something went wrong' });
17 | } else {
18 | response.send(result);
19 | }
20 | });
21 | });
22 |
23 | };
24 |
25 | var saveSettings = function(data, callback) {
26 | data.version = config.settings.version;
27 | config.settings = data;
28 | config.save();
29 | callback(null, "{ success }");
30 | };
--------------------------------------------------------------------------------
/app/api/smartthings.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | const app = express();
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 | var smartthings = new SelfReloadJSON(appRoot + '/data/smartthings.json');
9 |
10 | module.exports.set = function(app) {
11 | app.use(bodyParser.json());
12 |
13 | app.get('/api/smartthings/devices', (request, response) => {
14 | response.setHeader('Content-Type', 'application/json');
15 | getDevices(function(err, result) {
16 | if (err) {
17 | response.send(500, { error: 'something went wrong' });
18 | } else {
19 | response.send(result);
20 | }
21 | });
22 | });
23 |
24 | app.get('/api/smartthings/routines', (request, response) => {
25 | response.setHeader('Content-Type', 'application/json');
26 | getRoutines(function(err, result) {
27 | if (err) {
28 | response.send(500, { error: 'something went wrong' });
29 | } else {
30 | response.send(result);
31 | }
32 | });
33 | });
34 |
35 | app.post('/api/smartthings/routines/send/:id', (request, response) => {
36 | response.setHeader('Content-Type', 'application/json');
37 | runRoutine(request.params.id, function(err, result) {
38 | if (err) {
39 | response.send(500, { error: 'something went wrong' });
40 | } else {
41 | response.send(result);
42 | }
43 | });
44 | });
45 | app.get('/api/smartthings/locations', (request, response) => {
46 | response.setHeader('Content-Type', 'application/json');
47 | getLocations(function(err, result) {
48 | if (err) {
49 | response.send(500, { error: 'something went wrong' });
50 | } else {
51 | response.send(result);
52 | }
53 | });
54 | });
55 |
56 | app.get('/api/smartthings/modes', (request, response) => {
57 | response.setHeader('Content-Type', 'application/json');
58 | getModes(function(err, result) {
59 | if (err) {
60 | response.send(500, { error: 'something went wrong' });
61 | } else {
62 | response.send(result);
63 | }
64 | });
65 | });
66 |
67 | app.post('/api/smartthings/devices/save', (request, response) => {
68 | response.setHeader('Content-Type', 'application/json');
69 | saveDevices(request.body, function(err, result) {
70 | if (err) {
71 | response.send(500, { error: 'something went wrong' });
72 | } else {
73 | response.send(result);
74 | }
75 | });
76 | });
77 |
78 | app.post('/api/smartthings/routines/save', (request, response) => {
79 | response.setHeader('Content-Type', 'application/json');
80 | saveRoutines(request.body, function(err, result) {
81 | if (err) {
82 | response.send(500, { error: 'something went wrong' });
83 | } else {
84 | response.send(result);
85 | }
86 | });
87 | });
88 |
89 | app.post('/api/smartthings/locations/save', (request, response) => {
90 | response.setHeader('Content-Type', 'application/json');
91 | saveLocations(request.body, function(err, result) {
92 | if (err) {
93 | response.send(500, { error: 'something went wrong' });
94 | } else {
95 | response.send(result);
96 | }
97 | });
98 | });
99 |
100 | app.post('/api/smartthings/modes/save', (request, response) => {
101 | response.setHeader('Content-Type', 'application/json');
102 | saveModes(request.body, function(err, result) {
103 | if (err) {
104 | response.send(500, { error: 'something went wrong' });
105 | } else {
106 | response.send(result);
107 | }
108 | });
109 | });
110 |
111 | app.get('/api/smartthings/devices/:id/:command/:value', (request, response) => {
112 | response.setHeader('Content-Type', 'application/json');
113 | sendCommand(request.params.id, request.params.command, request.params.value, function(err, result) {
114 | if (err) {
115 | response.send(500, { error: 'something went wrong' });
116 | } else {
117 | response.send(result);
118 | }
119 | });
120 | });
121 |
122 | app.get('/api/smartthings/devices/:id/:command/', (request, response) => {
123 | response.setHeader('Content-Type', 'application/json');
124 | sendCommand(request.params.id, request.params.command, null, function(err, result) {
125 | if (err) {
126 | response.send(500, { error: 'something went wrong' });
127 | } else {
128 | response.send(result);
129 | }
130 | });
131 | });
132 |
133 | };
134 |
135 | var sendCommand = function(id, cmd, value, callback) {
136 | var endpoint = "/devices/" + id + "/" + cmd + "";
137 | if (value) { endpoint += "/" + value }
138 | //var token = config.settings.token;
139 | var url = config.settings.apiUrl + endpoint + '?access_token=' + config.settings.token;
140 |
141 | request({
142 | url: url,
143 | json: true
144 | }, function(error, response, body) {
145 |
146 | if (!error && response.statusCode === 200) {
147 | callback(null, body);
148 | } else {
149 | callback(error);
150 | }
151 | });
152 | };
153 |
154 | var getDevices = function(callback) {
155 | var endpoint = "/allDevices";
156 | var token = config.settings.token;
157 | var url = config.settings.apiUrl + endpoint + '?access_token=' + token;
158 |
159 | request({
160 | url: url,
161 | json: true
162 | }, function(error, response, body) {
163 |
164 | if (!error && response.statusCode === 200) {
165 | body.forEach((d) => {
166 | for (var x in d.attributes) {
167 | d.attributes[x] = d.attributes[x] != null ? d.attributes[x].replace(/\n/g, " ") : d.attributes[x];
168 | }
169 | });
170 | callback(null, body);
171 | } else {
172 | callback(error);
173 | }
174 | });
175 | };
176 |
177 | var getRoutines = function(callback) {
178 | var endpoint = "/routines";
179 | var token = config.settings.token;
180 | var url = config.settings.apiUrl + endpoint + '?access_token=' + token;
181 |
182 | request({
183 | url: url,
184 | json: true
185 | }, function(error, response, body) {
186 |
187 | if (!error && response.statusCode === 200) {
188 | callback(null, body);
189 | } else {
190 | callback(error);
191 | }
192 | });
193 | };
194 |
195 | var runRoutine = function(id, callback) {
196 | var endpoint = "/routines/" + id;
197 | var token = config.settings.token;
198 | var url = config.settings.apiUrl + endpoint + '?access_token=' + token;
199 |
200 | request.post({
201 | headers: { 'content-type': 'application/x-www-form-urlencoded' },
202 | url: url,
203 | json: true,
204 |
205 | }, function(error, response, body) {
206 |
207 | if (!error && response.statusCode === 200) {
208 | callback(null, body);
209 | } else {
210 | callback(error);
211 | }
212 | });
213 | };
214 |
215 | var getLocations = function(callback) {
216 | var endpoint = "/locations";
217 | var token = config.settings.token;
218 | var url = config.settings.apiUrl + endpoint + '?access_token=' + token;
219 |
220 | request({
221 | url: url,
222 | json: true
223 | }, function(error, response, body) {
224 |
225 | if (!error && response.statusCode === 200) {
226 | callback(null, body);
227 | } else {
228 | callback(error);
229 | }
230 | });
231 | };
232 |
233 | var getModes = function(callback) {
234 | var endpoint = "/modes";
235 | var token = config.settings.token;
236 | var url = config.settings.apiUrl + endpoint + '?access_token=' + token;
237 |
238 | request({
239 | url: url,
240 | json: true
241 | }, function(error, response, body) {
242 |
243 | if (!error && response.statusCode === 200) {
244 | callback(null, body);
245 | } else {
246 | callback(error);
247 | }
248 | });
249 | };
250 |
251 | var saveDevices = function(data, callback) {
252 | data.forEach(d => {
253 | for (var x in d.attributes) {
254 | if (x == "stream") {
255 | var fixed = JSON.stringify(d.attributes[x])
256 | d.attributes[x] = fixed;
257 | }
258 | }
259 | })
260 | smartthings.devices = data;
261 | smartthings.save();
262 | callback(null, "{ success }");
263 | };
264 |
265 | var saveRoutines = function(data, callback) {
266 | smartthings.routines = data;
267 | smartthings.save();
268 | callback(null, "{ success }");
269 | };
270 |
271 | var saveLocations = function(data, callback) {
272 | smartthings.locations = data;
273 | smartthings.save();
274 | callback(null, "{ success }");
275 | };
276 |
277 | var saveModes = function(data, callback) {
278 | smartthings.modes = data;
279 | smartthings.save();
280 | callback(null, "{ success }");
281 | };
--------------------------------------------------------------------------------
/app/api/styles.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | const app = express();
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
9 |
10 | module.exports.set = function(app) {
11 | app.use(bodyParser.json());
12 |
13 | app.get('/api/styles/:id', (request, response) => {
14 | response.setHeader('Content-Type', 'application/json');
15 | getStyle(request.params.id, function(err, result) {
16 | if (err) {
17 | response.status(500).send({ error: err });
18 | } else {
19 | response.send(result);
20 | }
21 | });
22 | });
23 |
24 | app.delete('/api/styles/:id', (request, response) => {
25 | response.setHeader('Content-Type', 'application/json');
26 | deleteStyle(request.params.id, function(err, result) {
27 | if (err) {
28 | response.status(500).send({ error: err });
29 | } else {
30 | response.send(result);
31 | }
32 | });
33 | });
34 |
35 | app.post('/api/styles/:id/save', (request, response) => {
36 | response.setHeader('Content-Type', 'application/json');
37 | saveStyle(request.params.id, request.body, function(err, result) {
38 | if (err) {
39 | response.status(500).send({ error: err });
40 | } else {
41 | response.send(result);
42 | }
43 | });
44 | });
45 | }
46 |
47 | var getStyle = function(tempid, callback) {
48 | var style = {};
49 | if (tempid == "0") {
50 | style.css = Buffer.from(styles.styles.global, 'base64').toString();
51 | style.name = "global";
52 | } else {
53 | style.css = Buffer.from(styles.styles.dashboards[tempid - 1].css, 'base64').toString();
54 | style.name = styles.styles.dashboards[tempid - 1].name;
55 | }
56 | callback(null, style)
57 | }
58 |
59 | var saveStyle = function(id, body, callback) {
60 | var style = new Buffer(body.content).toString("base64");
61 | if (id == "0") {
62 | styles.styles.global = style;
63 | } else {
64 | id--;
65 | if (styles.styles.dashboards[id]) {
66 | styles.styles.dashboards[id].css = style;
67 | styles.styles.dashboards[id].name = body.name;
68 | styles.styles.dashboards[id].id = id; //this may not be right...
69 | } else {
70 | var t = {};
71 | t.id = id;
72 | t.css = style;
73 | t.name = body.name
74 | styles.styles.dashboards.push(t);
75 | }
76 | }
77 | styles.save();
78 | callback(null, "success")
79 | }
80 |
81 | var deleteStyle = function(id, callback) {
82 | if (id != "global") {
83 | styles.styles.dashboards.splice([id - 1], 1);
84 | styles.save();
85 | }
86 | callback(null, "success");
87 | };
--------------------------------------------------------------------------------
/app/api/templates.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | const app = express();
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 | var templates = new SelfReloadJSON(appRoot + '/data/templates.json');
9 |
10 | module.exports.set = function(app) {
11 | app.use(bodyParser.json());
12 |
13 | app.get('/api/templates/:id', (request, response) => {
14 | response.setHeader('Content-Type', 'application/json');
15 | getTemplate(request.params.id, function(err, result) {
16 | if (err) {
17 | response.status(500).send({ error: err });
18 | } else {
19 | response.send(result);
20 | }
21 | });
22 | });
23 |
24 | app.delete('/api/templates/:id', (request, response) => {
25 | response.setHeader('Content-Type', 'application/json');
26 | deleteTemplate(request.params.id, function(err, result) {
27 | if (err) {
28 | response.status(500).send({ error: err });
29 | } else {
30 | response.send(result);
31 | }
32 | });
33 | });
34 |
35 | app.post('/api/templates/:id/save', (request, response) => {
36 | response.setHeader('Content-Type', 'application/json');
37 | saveTemplate(request.params.id, request.body, function(err, result) {
38 | if (err) {
39 | response.status(500).send({ error: err });
40 | } else {
41 | response.send(result);
42 | }
43 | });
44 | });
45 | }
46 |
47 | var getTemplate = function(tempid, callback) {
48 | var template = {};
49 | template.css = Buffer.from(templates.templates[tempid].content, 'base64').toString();
50 | template.name = templates.templates[tempid].id;
51 | callback(null, template)
52 | }
53 |
54 | var saveTemplate = function(id, body, callback) {
55 | var template = new Buffer(body.content).toString("base64");
56 | if (templates.templates[id]) {
57 | templates.templates[id].content = template;
58 | templates.templates[id].id = body.name;
59 | } else {
60 | var t = {};
61 | t.id = body.name;
62 | t.content = template
63 | templates.templates.push(t);
64 | }
65 | templates.save();
66 | callback(null, "success")
67 | }
68 |
69 | var deleteTemplate = function(id, callback) {
70 | templates.templates.splice([id], 1);
71 | templates.save();
72 | callback(null, "success");
73 | };
--------------------------------------------------------------------------------
/app/api/weather.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | const app = express();
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 |
9 | module.exports.set = function(app) {
10 | app.use(bodyParser.json());
11 |
12 | app.get('/api/weather', (request, response) => {
13 | response.setHeader('Content-Type', 'application/json');
14 | getWeather(function(err, result) {
15 | if (err) {
16 | response.status(500).send({ error: err });
17 | } else {
18 | response.send(result);
19 | }
20 | });
21 | });
22 |
23 | var getWeather = function(callback) {
24 | var endpoint = "/weather";
25 | var token = config.settings.token;
26 | var url = config.settings.apiUrl + endpoint + '?access_token=' + token;
27 | //console.log("getting devices from " + url);
28 |
29 | request({
30 | url: url,
31 | json: true
32 | }, function(error, response, body) {
33 | if (error) {
34 | callback(error)
35 | }
36 | if (!error && response.statusCode === 200) {
37 | callback(null, body);
38 | }
39 | });
40 | };
41 |
42 | }
--------------------------------------------------------------------------------
/app/controllers/cameras.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const exphbs = require('express-handlebars');
4 | var SelfReloadJSON = require('self-reload-json');
5 | const bodyParser = require('body-parser');
6 | const appRoot = require('app-root-path');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 | var cameras = new SelfReloadJSON(appRoot + '/data/cameras.json');
9 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
10 |
11 | module.exports.set = function(app) {
12 |
13 | app.get('/cameras', (request, response) => {
14 | var css = Buffer.from(styles.styles.global, 'base64').toString();
15 | response.render('cameras', {
16 | version: config.settings.version,
17 | cameras: cameras.cameras,
18 | css: css
19 | });
20 | });
21 | }
--------------------------------------------------------------------------------
/app/controllers/dashboards.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const exphbs = require('express-handlebars');
4 | var SelfReloadJSON = require('self-reload-json');
5 | const fs = require('fs');
6 | const bodyParser = require('body-parser');
7 | const appRoot = require('app-root-path');
8 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
9 | var dashboards = new SelfReloadJSON(appRoot + '/data/dashboards.json');
10 | var smartthings = new SelfReloadJSON(appRoot + '/data/smartthings.json');
11 | var cameras = new SelfReloadJSON(appRoot + '/data/cameras.json');
12 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
13 | var templates = new SelfReloadJSON(appRoot + '/data/templates.json');
14 |
15 | module.exports.set = function(app) {
16 |
17 | app.get('/dashboards', (request, response) => {
18 | var css = Buffer.from(styles.styles.global, 'base64').toString();
19 | response.render('dashboards', {
20 | version: config.settings.version,
21 | dashboards: dashboards.dashboards,
22 | css: css
23 | });
24 | });
25 |
26 |
27 | app.get('/dashboards/:id', (request, response) => {
28 | var dashboard = {};
29 | dashboards.dashboards.forEach((dash) => {
30 | if (dash.id == request.params.id) {
31 | dashboard = dash
32 | }
33 | });
34 | var globalcss = Buffer.from(styles.styles.global, 'base64').toString();
35 | var css = "";
36 | for (var s in styles.styles.dashboards) {
37 | if (dashboard.css) {
38 | if (s == dashboard.css.toString()) {
39 | css = Buffer.from(styles.styles.dashboards[s].css, 'base64').toString();
40 | }
41 | }
42 | }
43 | response.render('dashboard', {
44 | version: config.settings.version,
45 | dashboard: dashboard,
46 | dashcss: css,
47 | css: globalcss
48 | });
49 | });
50 |
51 | app.get('/dashboards/:id/edit', (request, response) => {
52 | //Build list of devices here...
53 | var sortedDevices = []
54 | smartthings.devices.forEach(d => {
55 | d.api = "smartthings";
56 | sortedDevices.push(d);
57 | });
58 | if (smartthings.routines) {
59 | smartthings.routines.forEach(r => {
60 | r.api = "smartthings";
61 | r.name = r.label;
62 | r.commands = [{ command: "toggle" }];
63 | r.type = "Routine";
64 | sortedDevices.push(r);
65 | })
66 | }
67 | sortedDevices = sortedDevices.sort(sortByType);
68 | var dashboard = {};
69 | dashboards.dashboards.forEach((dash) => {
70 | if (dash.id == request.params.id) {
71 | dashboard = dash;
72 | }
73 | });
74 | var sortedDashDevices = dashboard.devices.sort(sortByOrder);
75 | var style = []
76 | styles.styles.dashboards.forEach(temp => {
77 | style.push({ name: temp.name, css: Buffer.from(temp.css, 'base64').toString() })
78 | });
79 | response.render('dashboard-edit', {
80 | version: config.settings.version,
81 | dashboard: dashboard,
82 | dashDevices: sortedDashDevices,
83 | devices: sortedDevices,
84 | cameras: cameras.cameras,
85 | css: style
86 | });
87 | });
88 |
89 | app.get('/dashboards/:id/device/:dashDevId', (request, response) => {
90 | var dashboard = {};
91 | for (var d in dashboards.dashboards) {
92 | if (dashboards.dashboards[d].id == request.params.id) {
93 | dashboard = dashboards.dashboards[d];
94 | }
95 | }
96 | var device = {};
97 | dashboard.devices.forEach((dev) => {
98 | if (dev.dashDevId == request.params.dashDevId) {
99 | device = dev
100 | }
101 | });
102 |
103 | //get device templates
104 | var temps = templates.templates.map(e => e.id.toLowerCase());
105 |
106 | //console.log(sortedDevices);
107 | var css = Buffer.from(styles.styles.global, 'base64').toString();
108 | response.render('dashboard-device', {
109 | version: config.settings.version,
110 | dashboard: dashboard,
111 | device: device,
112 | templates: temps,
113 | css: css
114 | });
115 | });
116 |
117 | function sortByType(x, y) {
118 | return ((x.type == y.type) ? 0 : ((x.type > y.type) ? 1 : -1));
119 | }
120 |
121 | function sortByOrder(x, y) {
122 | return ((parseInt(x.order) == parseInt(y.order)) ? 0 : ((parseInt(x.order) > parseInt(y.order)) ? 1 : -1));
123 | }
124 | };
--------------------------------------------------------------------------------
/app/controllers/device.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const bodyParser = require('body-parser');
4 | const app = express();
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | const hbs = require('handlebars');
8 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
9 | var dashboards = new SelfReloadJSON(appRoot + '/data/dashboards.json');
10 | var templates = new SelfReloadJSON(appRoot + '/data/templates.json');
11 |
12 | module.exports.set = function(app) {
13 |
14 | app.get('/device/:dashId/:id', (request, response) => {
15 | getTile(request.params.dashId, request.params.id, function(err, result) {
16 | //var template = "devices/default";
17 |
18 | /*if (result.template) {
19 | template = "devices/" + result.template.toLowerCase();
20 | }*/
21 | var t = "0";
22 |
23 | for (i = 0; i < templates.templates.length; i++) {
24 | if (templates.templates[i].id.toLowerCase() == result.template) {
25 | t = i;
26 | }
27 | }
28 |
29 | var template = Buffer.from(templates.templates[t].content, 'base64').toString();
30 | var compiled = hbs.compile(template);
31 | var html = compiled({ device: result });
32 |
33 | response.send(html);
34 | response.end();
35 |
36 | /*
37 | response.render(template, {
38 | layout: false,
39 | version: config.settings.version,
40 | device: result
41 | });*/
42 | });
43 | });
44 | };
45 |
46 | var getTile = function(dashId, id, callback) {
47 | var dashboard = {};
48 | dashboards.dashboards.forEach((dash) => {
49 | if (dash.id == dashId) {
50 | dashboard = dash
51 | }
52 | });
53 | var device = null;
54 | dashboard.devices.forEach((dev) => {
55 | if (dev.dashDevId == id) {
56 | device = dev;
57 | };
58 | });
59 | //var type = device.type;
60 | callback(null, device)
61 | };
--------------------------------------------------------------------------------
/app/controllers/home.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | var SelfReloadJSON = require('self-reload-json');
4 | const appRoot = require('app-root-path');
5 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
6 | var dashboards = new SelfReloadJSON(appRoot + '/data/dashboards.json');
7 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
8 |
9 | module.exports.set = function(app) {
10 |
11 | app.get('/', (request, response) => {
12 | var css = Buffer.from(styles.styles.global, 'base64').toString();
13 | response.render('home', {
14 | version: config.settings.version,
15 | dashboards: dashboards.dashboards,
16 | css: css
17 | });
18 | });
19 | }
--------------------------------------------------------------------------------
/app/controllers/importexport.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | var SelfReloadJSON = require('self-reload-json');
4 | const appRoot = require('app-root-path');
5 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
6 | var dashboards = new SelfReloadJSON(appRoot + '/data/dashboards.json');
7 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
8 | var templates = new SelfReloadJSON(appRoot + '/data/templates.json');
9 |
10 | module.exports.set = function(app) {
11 |
12 | app.get('/importexport', (request, response) => {
13 | var css = Buffer.from(styles.styles.global, 'base64').toString();
14 | response.render('importexport', {
15 | version: config.settings.version,
16 | styles: styles.styles,
17 | templates: templates.templates,
18 | css: css
19 | });
20 | });
21 | }
--------------------------------------------------------------------------------
/app/controllers/index.js:
--------------------------------------------------------------------------------
1 | var home = require('./home');
2 | var smartthings = require('./smartthings');
3 | var device = require('./device');
4 | var dashboards = require('./dashboards');
5 | var settings = require('./settings');
6 | var updates = require('./updates');
7 | var cameras = require('./cameras');
8 | var templates = require('./templates');
9 | var styles = require('./styles');
10 | var importexport = require('./importexport');
11 |
12 | module.exports.set = function(app) {
13 | home.set(app);
14 | smartthings.set(app);
15 | device.set(app);
16 | dashboards.set(app);
17 | settings.set(app);
18 | updates.set(app);
19 | cameras.set(app);
20 | templates.set(app);
21 | styles.set(app);
22 | importexport.set(app);
23 | }
--------------------------------------------------------------------------------
/app/controllers/settings.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const exphbs = require('express-handlebars');
4 | const request = require('request');
5 | var SelfReloadJSON = require('self-reload-json');
6 | const appRoot = require('app-root-path');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 | const dashboards = require('../../data/dashboards.json');
9 | var smartthings = new SelfReloadJSON(appRoot + '/data/smartthings.json');
10 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
11 | const simpleOauthModule = require('simple-oauth2');
12 | var ip = require('ip');
13 | var oauth2;
14 | var accessURL;
15 | var authorizationUri;
16 | var endpoints_uri = 'https://graph.api.smartthings.com/api/smartapps/endpoints';
17 |
18 |
19 | module.exports.set = function(app) {
20 |
21 | app.get('/settings', (request, response) => {
22 | var css = Buffer.from(styles.styles.global, 'base64').toString();
23 | response.render('settings', {
24 | version: config.settings.version,
25 | settings: config.settings,
26 | css: css
27 | });
28 | });
29 |
30 | app.get('/settings/auth', function(req, res) {
31 | //console.log(authorizationUri)';
32 | try {
33 | initOauth();
34 | } catch (err) {
35 | console.log("no client or secret set");
36 | }
37 | res.redirect(authorizationUri);
38 | });
39 |
40 | app.get('/settings/callback', function(req, res) {
41 | const code = req.query.code;
42 | try {
43 | initOauth();
44 | } catch (err) {
45 | console.log("no client or secret set");
46 | }
47 | var redirectUrl = "http://" + ip.address() + ":3000/settings/callback";
48 |
49 | oauth2.authorizationCode.getToken({
50 | code: code,
51 | redirect_uri: redirectUrl
52 | }, saveToken);
53 |
54 | function saveToken(error, result) {
55 | if (error) {
56 | console.log('Access Token Error', error.message);
57 | } else {
58 | config.settings.token = result.access_token;
59 |
60 | var sendreq = {
61 | method: "GET",
62 | uri: endpoints_uri + "?access_token=" + result.access_token
63 | };
64 | request(sendreq, function(err, res1, body) {
65 | var endpoints = JSON.parse(body);
66 | //TODO store locations information location.id and location.home
67 | //console.log(endpoints);
68 | // we just show the final access URL and Bearer code
69 | var access_url = endpoints[0].url
70 |
71 | accessURL = 'https://graph.api.smartthings.com/' + access_url;
72 | apiURL = endpoints[0].uri;
73 |
74 | config.settings.apiUrl = apiURL;
75 | config.save();
76 | res.render('settings', {
77 | version: config.settings.version,
78 | settings: config.settings
79 | });
80 |
81 | });
82 | }
83 | }
84 | });
85 |
86 | app.get('/settings/endpoints', function(req, res) {
87 | var response = "";
88 | var options = {
89 | uri: endpoints_uri + "?access_token=" + token,
90 | method: 'GET',
91 | headers: {
92 | 'Content-Type': 'application/json',
93 | 'Authorization': 'Bearer ' + token
94 | }
95 | };
96 | request(options, function(err, res1, body) {
97 | var endpoints = JSON.parse(body);
98 | res.send('endpoints are: ' + endpoints[0].location.name + endpoints[0].uri);
99 | });
100 | });
101 |
102 | var initOauth = function() {
103 | oauth2 = simpleOauthModule.create({
104 | client: {
105 | id: config.settings.clientId,
106 | secret: config.settings.clientSecret
107 | },
108 | auth: {
109 | tokenHost: 'https://graph.api.smartthings.com',
110 | tokenPath: '/oauth/token',
111 | authorizePath: '/oauth/authorize',
112 | },
113 | });
114 | var redirectUrl = "http://" + ip.address() + ":3000/settings/callback";
115 | authorizationUri = oauth2.authorizationCode.authorizeURL({
116 | redirect_uri: redirectUrl,
117 | scope: 'app',
118 | state: '3(#0/!~'
119 | });
120 | };
121 | };
--------------------------------------------------------------------------------
/app/controllers/smartthings.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const app = express();
4 | var SelfReloadJSON = require('self-reload-json');
5 | const appRoot = require('app-root-path');
6 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
7 | var smartthings = new SelfReloadJSON(appRoot + '/data/smartthings.json');
8 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
9 |
10 | module.exports.set = function(app) {
11 |
12 | app.get('/smartthings', (request, response) => {
13 | var devices = smartthings.devices;
14 | var routines = smartthings.routines;
15 | var locations = smartthings.locations;
16 | var modes = smartthings.modes;
17 | var css = Buffer.from(styles.styles.global, 'base64').toString();
18 |
19 | response.render('smartthings', {
20 | version: config.settings.version,
21 | devices: devices,
22 | routines: routines,
23 | locations: locations,
24 | modes: modes,
25 | css: css
26 | });
27 | });
28 |
29 | };
--------------------------------------------------------------------------------
/app/controllers/styles.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const app = express();
4 | var SelfReloadJSON = require('self-reload-json');
5 | const appRoot = require('app-root-path');
6 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
7 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
8 |
9 | module.exports.set = function(app) {
10 |
11 | app.get('/styles', (request, response) => {
12 | var style = []
13 | style.push({ "name": "global", "css": Buffer.from(styles.styles.global, 'base64').toString() });
14 | styles.styles.dashboards.forEach(temp => {
15 | style.push({ name: temp.name, css: Buffer.from(temp.css, 'base64').toString() })
16 | });
17 | var css = Buffer.from(styles.styles.global, 'base64').toString();
18 | response.render('styles', {
19 | version: config.settings.version,
20 | styles: style,
21 | css: css
22 | });
23 | });
24 |
25 | app.get('/styles/:id', (request, response) => {
26 | var style = []
27 | style.push({ "name": "global", "css": Buffer.from(styles.styles.global, 'base64').toString() });
28 | styles.styles.dashboards.forEach(temp => {
29 | style.push({ name: temp.name, css: Buffer.from(temp.css, 'base64').toString() })
30 | });
31 | var css = Buffer.from(styles.styles.global, 'base64').toString();
32 | response.render('styles', {
33 | version: config.settings.version,
34 | styles: style,
35 | css: css,
36 | id: request.params.id
37 | });
38 | });
39 | };
--------------------------------------------------------------------------------
/app/controllers/templates.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const app = express();
4 | var SelfReloadJSON = require('self-reload-json');
5 | const appRoot = require('app-root-path');
6 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
7 | var templates = new SelfReloadJSON(appRoot + '/data/templates.json');
8 | var styles = new SelfReloadJSON(appRoot + '/data/styles.json');
9 |
10 | module.exports.set = function(app) {
11 |
12 | app.get('/templates', (request, response) => {
13 | var temps = []
14 | templates.templates.forEach(temp => {
15 | temps.push({ id: temp.id, content: Buffer.from(temp.content, 'base64').toString() })
16 | });
17 | var css = Buffer.from(styles.styles.global, 'base64').toString();
18 | response.render('templates', {
19 | version: config.settings.version,
20 | templates: temps,
21 | css: css
22 | });
23 | });
24 | app.get('/templates/:id', (request, response) => {
25 | var temps = []
26 | templates.templates.forEach(temp => {
27 | temps.push({ id: temp.id, content: Buffer.from(temp.content, 'base64').toString() })
28 | });
29 | var css = Buffer.from(styles.styles.global, 'base64').toString();
30 | response.render('templates', {
31 | version: config.settings.version,
32 | templates: temps,
33 | css: css,
34 | id: request.params.id
35 | });
36 | });
37 | };
--------------------------------------------------------------------------------
/app/controllers/updates.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const app = express();
4 | var SelfReloadJSON = require('self-reload-json');
5 | const appRoot = require('app-root-path');
6 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
7 | var updates = new SelfReloadJSON(appRoot + '/data/updates.json');
8 |
9 | var doUpdates = false;
10 |
11 | module.exports.set = function(app) {
12 | app.get('/updates', function(req, res) {
13 | res.setHeader('Content-Type', 'application/json');
14 | if (config.settings.token != "") {
15 | doUpdates = true;
16 | } else {
17 | doUpdates = false
18 | }
19 | getUpdates(function(err, result) {
20 | if (err) {
21 | res.send(500, { error: 'something went wrong' });
22 | } else {
23 | updates.updates = result;
24 | updates.save();
25 | res.send(result);
26 | }
27 | });
28 | });
29 |
30 | setInterval(function() {
31 | if (doUpdates) {
32 | getUpdates(function(err, result) {
33 | if (err) {
34 | console.log('something went wrong');
35 | } else {
36 | updates.updates = result;
37 | updates.save();
38 | }
39 | });
40 | }
41 | }, 5000);
42 |
43 | var getUpdates = function(callback) {
44 | var endpoint = "/updates";
45 | var token = config.settings.token;
46 | var url = config.settings.apiUrl + endpoint + '?access_token=' + token;
47 | //console.log("getting updates from " + url);
48 |
49 | request({
50 | url: url,
51 | json: true
52 | }, function(error, response, body) {
53 |
54 | if (!error && response.statusCode === 200) {
55 | callback(null, body);
56 | } else {
57 | callback(error);
58 | }
59 | });
60 | };
61 | };
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | var port = 3000;
4 | const path = require('path');
5 | const request = require('request');
6 | const exphbs = require('express-handlebars');
7 | var controllers = require('./controllers');
8 | const appRoot = require('app-root-path');
9 | var SelfReloadJSON = require('self-reload-json');
10 | var config = new SelfReloadJSON(appRoot + '/data/settings.json');
11 | var api = require('./api/');
12 |
13 | if (config.settings.port) {
14 | port = config.settings.port;
15 | }
16 | controllers.set(app);
17 | api.set(app);
18 | app.use(express.static('public'));
19 |
20 | app.listen(port, (err) => {
21 | if (err) {
22 | return console.log('something bad happened', err);
23 | }
24 |
25 | console.log(`server is listening on ${port}`);
26 | });
27 |
28 | app.engine('.hbs', exphbs({
29 | defaultLayout: 'main',
30 | extname: '.hbs',
31 | layoutsDir: path.join(__dirname, 'views/layouts')
32 | }));
33 |
34 | app.set('view engine', '.hbs');
35 | app.set('views', path.join(__dirname, 'views'));
36 |
37 | //enable caching
38 | //app.enable('view cache');
--------------------------------------------------------------------------------
/app/views/cameras.hbs:
--------------------------------------------------------------------------------
1 |
Add ability to get latest values here...
38 | {{#each device.attributes}} {{@key}}: {{this}}For future use, enable/disable commands to send
43 | {{#each device.commands}} {{command}}13 | | Display Name | 14 |Type | 15 |API | 16 |
---|---|---|---|
20 | | {{name}} | 21 |{{type}} | 22 |{{api}} | 23 |
75 | | Name | 76 |Type | 77 |Template | 78 |Edit | 79 |
---|---|---|---|---|
83 | | {{name}} | 84 |{{type}} | 85 |{{template}} | 86 |edit | 87 |
An open-source project built from the ground up...
8 |Donate your Time, Coding Skills, Design Skills, Testing, feedback or even Money. Nothing in life 14 | is truely free, and your donation will go to fund the development and collaboration resources 15 | needed to keep this project going. 16 |
17 |Donations of $25USD or more will get a permanent shout out in our donators section and placement 18 | in the source code and application screens.
19 |This section allows you to import and export Templates and/or Styles and share them with others
17 |Please select a file to import containing Templates and/or Styles
20 | 27 |39 | | Name | 40 |
---|---|
44 | | Global | 45 |
50 | | {{name}} | 51 |
60 | | Name | 61 |
---|---|
66 | | {{id}} | 67 |
Port to run on: (will have to restart node application to take effect)
5 | 6 |Enter this to skip the oauth2 process if you have manually installed the smartapp and already have a token and url
10 | 11 |Enter this to skip the oauth2 process
13 | 14 |Enter this if planning on using oauth2 install method
16 | 17 |Enter this if planning on using oauth2 install method
19 |16 | 17 | 18 | 19 |
20 | 21 |Id | 27 |Display Name | 28 |Type | 29 |Commands | 30 |Last Updated | 31 |
---|---|---|---|---|
{{id}} | 35 |{{name}} | 36 |{{type}} | 37 |{{#each commands}} {{command}}, {{/each}} 38 | | 39 |{{date}} | 40 |
48 | 49 | 50 | 51 |
52 |Label / Name | 58 |Id | 59 |
---|---|
{{label}} | 63 |{{id}} | 64 |
72 | 73 | 74 | 75 | 76 |
77 |94 | 95 | 96 | 97 |
98 |Id | Display Name | Type | Commands | Last Updated |
---|---|---|---|---|
" + data[i].id + " | " + data[i].name + " | " + data[i].type + " | " + JSON.stringify(data[i].commands) + " | " + data[i].date + " |
Label / Name | Id |
---|---|
" + data[i].label + " | " + data[i].id + " |