├── database
└── README.md
├── .npmignore
├── extensions
├── mp3
│ ├── RedAlert.mp3
│ ├── CloisterBell.mp3
│ ├── church-bells.mp3
│ └── Ringing-clock.mp3
├── blankExtension.js
├── mp3Extension.js
├── IFTTTExtension.js
├── rpioExtension.js
└── sayExtension.js
├── CHANGES.md
├── typings
├── index.d.ts
└── globals
│ ├── node
│ └── typings.json
│ ├── rpio
│ ├── typings.json
│ └── index.d.ts
│ ├── moment
│ └── typings.json
│ └── commander
│ └── typings.json
├── typings.json
├── .gitattributes
├── lib
├── brains
│ ├── controller.js
│ └── bitdogBrain.js
├── eventProcessor.js
├── alarm
│ ├── zone.js
│ ├── alarmMode.js
│ └── bitdogAlarm.js
├── zwave
│ ├── zwaveScene.js
│ ├── zwaveInstance.js
│ ├── zwaveClass.js
│ ├── zwaveHome.js
│ ├── zwaveCommandClasses.js
│ ├── zwaveNode.js
│ └── zwaveValue.js
├── automation
│ ├── weatherManager.js
│ ├── bitdogAutomation.js
│ ├── scheduler.js
│ └── eventCapturer.js
├── systemEvents.js
├── extensionBase.js
├── ipcManager.js
├── cameras
│ ├── websocketsProcess.js
│ ├── videoStreamer.js
│ ├── dvrManager.js
│ └── videoManager.js
└── constants.js
├── BitdogHub.sln
├── bin
├── motionHandler.js
└── bitdoghub
├── README.md
├── package.json
├── .gitignore
├── main.js
└── BitdogHub.njsproj
/database/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | obj/
2 | .ntvs_analysis.dat
3 | iotbridge.njsproj
4 | *.dll
5 | *.suo
6 | *.sln
7 |
8 |
--------------------------------------------------------------------------------
/extensions/mp3/RedAlert.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitdog-io/bitdog-hub/HEAD/extensions/mp3/RedAlert.mp3
--------------------------------------------------------------------------------
/extensions/mp3/CloisterBell.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitdog-io/bitdog-hub/HEAD/extensions/mp3/CloisterBell.mp3
--------------------------------------------------------------------------------
/extensions/mp3/church-bells.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitdog-io/bitdog-hub/HEAD/extensions/mp3/church-bells.mp3
--------------------------------------------------------------------------------
/extensions/mp3/Ringing-clock.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitdog-io/bitdog-hub/HEAD/extensions/mp3/Ringing-clock.mp3
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | # June 23, 2017
2 | Changed readme to better reflect project intent.
3 | Added weather API.
4 | Fixed automation start when there is no zwave configuration.
5 |
--------------------------------------------------------------------------------
/typings/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | ///
5 |
--------------------------------------------------------------------------------
/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "globalDependencies": {
3 | "commander": "registry:dt/commander#2.3.0+20160317120654",
4 | "moment": "registry:dt/moment#2.11.1+20161010105546",
5 | "node": "registry:dt/node#7.0.0+20170322231424",
6 | "rpio": "registry:dt/rpio#0.0.0+20160921181726"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/typings/globals/node/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/a4a912a0cd1849fa7df0e5d909c8625fba04e49d/node/index.d.ts",
5 | "raw": "registry:dt/node#7.0.0+20170322231424",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/a4a912a0cd1849fa7df0e5d909c8625fba04e49d/node/index.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/typings/globals/rpio/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/fb972b28d215806c57280990833b6e7102012056/rpio/index.d.ts",
5 | "raw": "registry:dt/rpio#0.0.0+20160921181726",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/fb972b28d215806c57280990833b6e7102012056/rpio/index.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/typings/globals/moment/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/637e7d6df755e785387d5269cb9287cdc51b8cb7/moment/moment.d.ts",
5 | "raw": "registry:dt/moment#2.11.1+20161010105546",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/637e7d6df755e785387d5269cb9287cdc51b8cb7/moment/moment.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/typings/globals/commander/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/commander/commander.d.ts",
5 | "raw": "registry:dt/commander#2.3.0+20160317120654",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/commander/commander.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/lib/brains/controller.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // controller.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
--------------------------------------------------------------------------------
/BitdogHub.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25123.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "BitdogHub", "BitdogHub.njsproj", "{38F4CFE3-F058-4502-A3AC-88A177BCE85C}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {38F4CFE3-F058-4502-A3AC-88A177BCE85C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {38F4CFE3-F058-4502-A3AC-88A177BCE85C}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {38F4CFE3-F058-4502-A3AC-88A177BCE85C}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {38F4CFE3-F058-4502-A3AC-88A177BCE85C}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/bin/motionHandler.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | //-----------------------------------------------------------------------------
4 | //
5 | // motionHandler.js
6 | //
7 | // Copyright (c) 2015-2017 Bitdog LLC.
8 | //
9 | // SOFTWARE NOTICE AND LICENSE
10 | //
11 | // This file is part of bitdog-hub.
12 | //
13 | // bitdog-hub is free software: you can redistribute it and/or modify
14 | // it under the terms of the GNU General Public License as published
15 | // by the Free Software Foundation, either version 3 of the License,
16 | // or (at your option) any later version.
17 | //
18 | // bitdog-hub is distributed in the hope that it will be useful,
19 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | // GNU General Public License for more details.
22 | //
23 | // You should have received a copy of the GNU General Public License
24 | // along with bitdog-hub. If not, see .
25 | //
26 | //-----------------------------------------------------------------------------
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Bitdog Hub implementation for Node.js
4 |
5 | [](http://badge.fury.io/js/bitdog-hub)
6 |
7 | [](https://nodei.co/npm/bitdog-hub/)
8 |
9 | [](https://nodei.co/npm/bitdog-hub/)
10 |
11 | [](http://badge.fury.io/gh/bitdog-io%2Fbitdog-hub)
12 |
13 |
14 | # Overview
15 | Bitdog Hub is a free home automation system for Node.js and Raspberry Pi. It enables the control of Z-Wave devices and local GPIO. To download
16 | the free mobile app or read more please visit our websites, [Bitdog Website](https://bitdog.io) and [Bitdog Cookbook](https://cookbook.bitdog.io)
17 |
18 | # Installation
19 | Although you can install bitdog-hub using NPM, we suggest following these [instructions](https://cookbook.bitdog.io/installing-bitdog-hub)
20 |
21 |
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bitdog-hub",
3 | "version": "2.0.16",
4 | "description": "Bitdog Home Security and Automation",
5 | "keywords": [ "iot" ,"z-wave", "zwave", "raspberry pi" ,"home automation" ,"sensor", "openzwave" ],
6 | "main": "./main.js",
7 | "homepage": "https://bitdog.io",
8 | "author": {
9 | "name": "Bitdog LLC",
10 | "email": "support@bitdog.io"
11 | },
12 | "bugs": {
13 | "email" : "support@bitdog.io",
14 | "url": "https://github.com/bitdog-io/bitdog-hub/issues"
15 | },
16 | "license": "GPL-3.0",
17 | "engines": {
18 | "node": ">=8.4.0"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/bitdog-io/bitdog-hub"
23 | },
24 | "bin": {
25 | "bitdoghub": "./bin/bitdoghub"
26 | },
27 | "dependencies": {
28 | "bitdog-client": "git+https://github.com/bitdog-io/bitdog-client.git#master",
29 | "commander": "^2.9.0",
30 | "moment": "^2.17.1",
31 | "openzwave-shared": "git+https://github.com/openzwave/node-openzwave-shared.git#master",
32 | "suncalc": "^1.7.0",
33 | "tingodb": "^0.4.2",
34 | "ws": "^3.1.0",
35 | "request": "^2.83.0"
36 | },
37 | "optionalDependencies": {
38 | "rpio": "^0.9.11"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/eventProcessor.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // eventProcessor.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 | function EventProcessor() {
26 |
27 | }
28 |
29 | EventProcessor.prototype.processMessage = function (message) {
30 | this.onProcessMessage(message);
31 | }
32 |
33 | EventProcessor.prototype.onProcessMessage = function (message) {
34 |
35 | }
36 |
37 | module.exports.EventProcessor = EventProcessor;
--------------------------------------------------------------------------------
/lib/alarm/zone.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zone.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | var alarmMode = require('./alarmMode.js');
28 |
29 | function Zone() {
30 | var _name = '';
31 | var _nodes = [];
32 | var _zwaveNodes = [];
33 | var _id = '';
34 | var _alarmMode = alarmMode.Disarmed;
35 |
36 | this.__defineGetter__("name", function () { return _name; });
37 | this.__defineSetter__("name", function (value) { _name = value; });
38 | this.__defineGetter__("id", function () { return _id; });
39 | }
40 |
41 | module.exports = Zone;
--------------------------------------------------------------------------------
/lib/zwave/zwaveScene.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zwaveScene.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | function ZWaveScene(homeId, id, label, values) {
28 | var _id = id;
29 | var _homeId = homeId;
30 | var _label = label;
31 | var _values = values;
32 |
33 |
34 | this.__defineGetter__("id", function () { return _id; });
35 | this.__defineGetter__("homeId", function () { return _homeId; });
36 | this.__defineGetter__("label", function () { return _label; });
37 | this.__defineSetter__("label", function (value) { _label = value; });
38 | this.__defineGetter__("values", function () { return _values; });
39 |
40 | }
41 |
42 | module.exports = ZWaveScene;
--------------------------------------------------------------------------------
/extensions/blankExtension.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // blankExtension.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | // Extension will inherit functions from ExtensionBase
27 | // Make sure the path to extensionBase is correct
28 | var ExtensionBase = require('../lib/extensionBase.js');
29 | var util = require('util');
30 |
31 | function Extension() {
32 | }
33 | // Extension inherits from ExtensionBase
34 | util.inherits(Extension, ExtensionBase);
35 |
36 | Extension.prototype.onMessage = function (message, configuration, logger) {
37 | };
38 |
39 | Extension.prototype.onInitialize = function (configuration, logger) {
40 | };
41 |
42 | // Export your Extension class so it can be loaded by the framework
43 | module.exports = Extension;
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Commenting this out is preferred by some people, see
24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
25 | node_modules
26 |
27 | # Users Environment Variables
28 | .lock-wscript
29 |
30 | # =========================
31 | # Operating System Files
32 | # =========================
33 |
34 | # OSX
35 | # =========================
36 |
37 | .DS_Store
38 | .AppleDouble
39 | .LSOverride
40 |
41 | # Thumbnails
42 | ._*
43 |
44 | # Files that might appear on external disk
45 | .Spotlight-V100
46 | .Trashes
47 |
48 | # Directories potentially created on remote AFP share
49 | .AppleDB
50 | .AppleDesktop
51 | Network Trash Folder
52 | Temporary Items
53 | .apdisk
54 |
55 | # Windows
56 | # =========================
57 |
58 | # Windows image file caches
59 | Thumbs.db
60 | ehthumbs.db
61 |
62 | # Folder config file
63 | Desktop.ini
64 |
65 | # Recycle Bin used on file shares
66 | $RECYCLE.BIN/
67 |
68 | # Windows Installer files
69 | *.cab
70 | *.msi
71 | *.msm
72 | *.msp
73 |
74 | # Windows shortcuts
75 | *.lnk
76 | obj
77 | .ntvs_analysis.dat
78 | *.dll
79 | *.suo
80 |
81 | /BitdogSA.VC.db
82 | /BitdogSA.VC.VC.opendb
83 | *.db
84 |
85 | /typings/globals/commander/index.d.ts
86 | /typings/globals/node/typings.json
87 | .ntvs_analysis.dat.tmp
88 |
--------------------------------------------------------------------------------
/lib/alarm/alarmMode.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // alarmMode.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | function AlarmMode() {
27 | this.__defineGetter__('away', function () { return 'Away'; });
28 | this.__defineGetter__('stay', function () { return 'Stay'; });
29 | this.__defineGetter__('disarmed', function () { return 'Disarmed'; });
30 | this.__defineGetter__('alarmed', function () { return 'Alarmed'; });
31 |
32 | this.__defineGetter__('securityAlarm', function () { return 'Security Alarm'; });
33 | this.__defineGetter__('safetyAlarm', function () { return 'Safety Alarm'; });
34 | this.__defineGetter__('alarmClear', function () { return 'Alarm Cleared'; });
35 |
36 | this.__defineGetter__('modes', function () { return [this.disarmed, this.stay, this.away]; });
37 |
38 | this.__defineGetter__('status', function () { return [this.safetyAlarm, this.securityAlarm, this.alarmClear]; });
39 | };
40 |
41 | module.exports = new AlarmMode();
--------------------------------------------------------------------------------
/lib/zwave/zwaveInstance.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zwaveInstance.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | var ZWaveValue = require('./zwaveValue.js');
28 |
29 | function ZWaveInstance(id) {
30 | var _id = id;
31 | var _values = [];
32 |
33 | this.updateValue = function (zwaveValueInfo) {
34 | var zwaveValue = getZWaveValue(zwaveValueInfo);
35 | return zwaveValue.updateValue(zwaveValueInfo);
36 | };
37 |
38 | this.removeValue = function (commandClassId, instanceId, valueIndex) {
39 | for (var index = 0; index < _values.length; index++) {
40 | if (_values[index].id == valueIndex) {
41 | _values.splice(index, 1);
42 | }
43 |
44 | return;
45 | }
46 | }
47 |
48 | this.getValue = function (indexId) {
49 | var zwaveValue = null;
50 | for (var index = 0; index < _values.length; index++) {
51 | if (_values[index].id == indexId) {
52 | zwaveValue = _values[index];
53 | break;
54 | }
55 | }
56 |
57 | return zwaveValue;
58 |
59 | }
60 |
61 | function getZWaveValue(zwaveValueInfo) {
62 | for (var index = 0; index < _values.length; index++) {
63 | if (_values[index].id == zwaveValueInfo.index)
64 | return _values[index];
65 | }
66 |
67 | var zwaveValue = new ZWaveValue(zwaveValueInfo);
68 | _values.push(zwaveValue);
69 |
70 | return zwaveValue;
71 | };
72 |
73 | this.__defineGetter__("id", function () { return _id; });
74 | this.__defineGetter__("values", function () { return _values; });
75 | }
76 |
77 | module.exports = ZWaveInstance;
--------------------------------------------------------------------------------
/lib/zwave/zwaveClass.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zwaveClass.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | var ZWaveInstance = require('./zwaveInstance.js');
28 | var zwaveCommandClasses = require('./zwaveCommandClasses.js');
29 |
30 |
31 | function ZWaveClass(id) {
32 | var _name = zwaveCommandClasses.getCommand(id);
33 | var _id = id;
34 | var _instances = [];
35 |
36 | this.updateValue = function (zwaveValueInfo) {
37 | var zwaveInstance = getZWaveInstance(zwaveValueInfo);
38 | return zwaveInstance.updateValue(zwaveValueInfo);
39 | };
40 |
41 | this.removeValue = function (commandClassId, instanceId, valueIndex) {
42 | for (var index = 0; index < _instances.length; index++) {
43 | if (_instances[index].id == instanceId) {
44 | var zwaveInstance = _instances[index];
45 | zwaveInstance.removeValue(commandClassId, instanceId, valueIndex);
46 |
47 | if (zwaveInstance.values.length < 1) {
48 | _instances.splice(index, 1);
49 | }
50 |
51 | return;
52 | }
53 | }
54 | }
55 |
56 | this.getValue = function (instanceId, indexId) {
57 | var zwaveInstance = null;
58 | for (var index = 0; index < _instances.length; index++) {
59 | if (_instances[index].id == instanceId) {
60 | zwaveInstance = _instances[index];
61 | break;
62 | }
63 | }
64 |
65 | if (zwaveInstance != null)
66 | return zwaveInstance.getValue(indexId);
67 | else
68 | return null;
69 | }
70 |
71 | function getZWaveInstance(zwaveValueInfo) {
72 | for (var index = 0; index < _instances.length; index++) {
73 | if (_instances[index].id == zwaveValueInfo.instance)
74 | return _instances[index];
75 | }
76 |
77 | var zwaveInstance = new ZWaveInstance(zwaveValueInfo.instance);
78 | _instances.push(zwaveInstance);
79 |
80 | return zwaveInstance;
81 | };
82 |
83 | this.__defineGetter__("name", function () { return _name; });
84 | this.__defineGetter__("id", function () { return _id; });
85 | this.__defineGetter__("instances", function () { return _instances; });
86 | }
87 |
88 | module.exports = ZWaveClass;
--------------------------------------------------------------------------------
/extensions/mp3Extension.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // mp3Extension.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | // Extension will inherit functions from ExtensionBase
28 | // Make sure the path to extensionBase is correct
29 | var ExtensionBase = require('../lib/extensionBase.js');
30 | var util = require('util');
31 | var child_process = require('child_process');
32 | var fs = require('fs');
33 | var path = require('path');
34 |
35 | // Create a class called Extension
36 | function Extension() {
37 | }
38 |
39 | // Extension inherits from ExtensionBase
40 | util.inherits(Extension, ExtensionBase);
41 |
42 | // Messages from and to this hub will pass through this function.
43 | // A good spot to watch for Z-Wave messages
44 | Extension.prototype.onMessage = function (message, configuration, logger) {
45 |
46 | // Messages will go through here, check them and do something.
47 | //logger.log('User', 'Got message and handling', message);
48 |
49 | };
50 |
51 | // This function will be called once during initialization.
52 | // Setup command and data capture here.
53 | Extension.prototype.onInitialize = function (configuration, logger) {
54 | var self = this;
55 | var filePath = path.resolve(path.dirname(__filename), './mp3');
56 | logger.logProcessEvent('mp3Extension', 'Loading files from file path', filePath);
57 | var files = fs.readdirSync(filePath);
58 | logger.logProcessEvent('mp3Extension', 'Found files', files);
59 |
60 | // Create a custom message schema with one string property.
61 | // add a list of values to the property that are file names
62 | var playMessageSchema = this.createMessageSchema('Play')
63 | .addStringProperty('sound', '', { values: files }, 'The file to play','Sound' );
64 |
65 |
66 | // Add a command to this hub that plays sound
67 | this.addCommand('Play Sound', playMessageSchema, function (message, configuration, logger) {
68 | var soundToPlay = message.sound;
69 |
70 | if (typeof soundToPlay !== typeof undefined && soundToPlay !== null && soundToPlay !== '') {
71 | var fileToPlay = path.resolve(filePath, soundToPlay);
72 | //child_process.spawn('omxplayer', [fileToPlay]);
73 | child_process.spawn('mplayer',[ '-af', 'volume=10:1', fileToPlay]);
74 | }
75 |
76 | });
77 |
78 |
79 | };
80 |
81 | // Export your Extension class so it can be loaded by the framework
82 | module.exports = Extension;
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/lib/zwave/zwaveHome.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zwaveHome.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | var ZWaveNode = require('./zwaveNode.js');
28 |
29 | function ZWaveHome() {
30 | var _homeId = "";
31 | var _nodes = [];
32 |
33 |
34 | this.createNode = function (nodeId, zwave) {
35 | var zwaveNode = new ZWaveNode(nodeId, zwave);
36 | _nodes.push(zwaveNode);
37 |
38 | return zwaveNode;
39 | };
40 |
41 | this.removeNode = function (nodeId) {
42 | var zwaveNode = null;
43 | for (var index = 0; index < _nodes.length; index++) {
44 | if (_nodes[index].id === nodeId) {
45 | zwaveNode = _nodes[index];
46 | _nodes.splice(index, 1);
47 | break;
48 | }
49 | }
50 |
51 | return zwaveNode;
52 | };
53 |
54 | this.updateValue = function (nodeId, zwaveValueInfo) {
55 | var zwaveNode = this.getNode(nodeId);
56 | return zwaveNode.updateValue(zwaveValueInfo);
57 | };
58 |
59 | this.removeValue = function (nodeId, commandClassId, instanceId, index) {
60 | var zwaveNode = this.getNode(nodeId);
61 | zwaveNode.removeValue(commandClassId, instanceId, index);
62 | };
63 |
64 | this.getValue = function (nodeId, commandClassId, instanceId, indexId) {
65 | var zwaveNode = this.getNode(nodeId);
66 |
67 | if (zwaveNode != null)
68 | return zwaveNode.getValue(commandClassId, instanceId, indexId);
69 | else
70 | return null;
71 | }
72 |
73 | this.setNodeInformation = function (nodeId, zwaveNodeInfo, ready) {
74 | var zwaveNode = this.getNode(nodeId);
75 |
76 | if (zwaveNode !== null)
77 | zwaveNode.setNodeInformation(zwaveNodeInfo,ready);
78 |
79 | return zwaveNode;
80 | };
81 |
82 | this.getNode = function (nodeId) {
83 | for (var index = 0; index < _nodes.length; index++) {
84 | if (_nodes[index].id === nodeId)
85 | return _nodes[index];
86 | }
87 |
88 | return null;
89 | };
90 |
91 | this.setNodeStatus = function (nodeId, status) {
92 | for (var index = 0; index < _nodes.length; index++) {
93 | if (_nodes[index].id === nodeId) {
94 | _nodes[index].status = status;
95 | break;
96 | }
97 | }
98 | };
99 |
100 | this.__defineGetter__("homeId", function () { return _homeId; });
101 | this.__defineSetter__("homeId", function (homeId) { _homeId = homeId; });
102 | this.__defineGetter__("nodes", function () { return _nodes; });
103 | }
104 |
105 | module.exports = ZWaveHome
--------------------------------------------------------------------------------
/lib/automation/weatherManager.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // weatherManager.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 | var bitdogClient = require('bitdog-client');
26 | var constants = require('../constants.js');
27 | var coreMessageSchemas = require('../coreMessageSchemas.js');
28 | var moment = require('moment');
29 |
30 | function WeatherManager() {
31 |
32 | /*
33 | Has it or will it rain / snow within X hour
34 | Current Temperature is over / under
35 | Today's max temperature is over / under
36 | Today's min temperature is over / under
37 | Today's avg temperature is over / under
38 | Today's cloud cover is over / under
39 | Today's precip is over / under
40 | Current humidity is over / under
41 | Current wind is over / under
42 | Today's max wind is over / under
43 | Today's min wind is over / under
44 | Current atmospheric pressure is over / under
45 | */
46 |
47 | var _forecasts = [];
48 | this.__defineGetter__('forecasts', function () { return _forecasts; });
49 |
50 | }
51 |
52 | WeatherManager.prototype.processWeatherForecast = function (weatherForecast) {
53 | var self = this;
54 |
55 | weatherForecast.timedate = moment();
56 |
57 | this.forecasts.push(weatherForecast);
58 |
59 | while (this.forecasts.length > 24 * 30) { this.forecasts.shift(); }
60 |
61 | bitdogClient.sendData('bd-weatherForecast', coreMessageSchemas.weatherForecastMessageSchema, function (message) {
62 | message.currentTemperatureC = weatherForecast.current.temp_c;
63 | message.currentTemperatureF = weatherForecast.current.temp_f;
64 | message.currentPressureIn = weatherForecast.current.pressure_in;
65 | message.currentPressureMb = weatherForecast.current.pressure_mb;
66 | message.currentWindDegree = weatherForecast.current.wind_degree;
67 | message.currentWindDirection = weatherForecast.current.wind_dir;
68 | message.currentWindKph = weatherForecast.current.wind_kph;
69 | message.currentWindMph = weatherForecast.current.wind_mph;
70 | message.todayAvgTemperatureC = weatherForecast.forecast.forecastday[0].day.avgtemp_c;
71 | message.todayAvgTemperatureF = weatherForecast.forecast.forecastday[0].day.avgtemp_f;
72 | message.todayMaxTemperatureC = weatherForecast.forecast.forecastday[0].day.maxtemp_c;
73 | message.todayMaxTemperatureF = weatherForecast.forecast.forecastday[0].day.maxtemp_f;
74 | message.todayMaxWindKph = weatherForecast.forecast.forecastday[0].day.maxwind_kph;
75 | message.todayMaxWindMph = weatherForecast.forecast.forecastday[0].day.maxwind_mph;
76 | message.todayMinTemperatureC = weatherForecast.forecast.forecastday[0].day.mintemp_c;
77 | message.todayMinTemperatureF = weatherForecast.forecast.forecastday[0].day.mintemp_f;
78 | message.todayTotalPrecipitationIn = weatherForecast.forecast.forecastday[0].day.totalprecip_in;
79 | message.todayTotalPrecipitationMm = weatherForecast.forecast.forecastday[0].day.totalprecip_mm;
80 | });
81 | }
82 |
83 |
84 | var weatherManager = new WeatherManager();
85 | module.exports = weatherManager; // singleton
--------------------------------------------------------------------------------
/lib/systemEvents.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // systemEvents.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | function EventInfo() {
27 |
28 | }
29 |
30 | function SystemEvents(bitdogHub, configuration, logger) {
31 |
32 | function publish(eventInfo) {
33 | bitdogHub.emit('system event', eventInfo, configuration, logger);
34 | }
35 |
36 | this.publishSystemStart = function () {
37 | var eventInfo = new EventInfo();
38 | eventInfo.name = 'system start';
39 | eventInfo.text = 'Bitdog Hub is starting';
40 |
41 | publish(eventInfo);
42 | };
43 |
44 | this.publishSystemStop = function () {
45 | var eventInfo = new EventInfo();
46 | eventInfo.name = 'system stop';
47 | eventInfo.text = 'Bitdog Hub is stopping, good bye';
48 |
49 | publish(eventInfo);
50 | };
51 |
52 | this.publishZWaveScanBegin = function () {
53 | var eventInfo = new EventInfo();
54 | eventInfo.name = 'zwave scan begin';
55 | eventInfo.text = 'Scanning ZWave network, please wait';
56 | publish(eventInfo);
57 | };
58 |
59 | this.publishZWaveScanEnd = function () {
60 | var eventInfo = new EventInfo();
61 | eventInfo.name = 'zwave scan end';
62 | eventInfo.text = 'Finished scanning ZWave network';
63 | publish(eventInfo);
64 | };
65 |
66 | this.publishSystemReady = function () {
67 | var eventInfo = new EventInfo();
68 | eventInfo.name = 'system ready';
69 | eventInfo.text = 'Bitdog Hub is now ready';
70 | publish(eventInfo);
71 | };
72 |
73 | this.publishSecurityArmAway = function () {
74 | var eventInfo = new EventInfo();
75 | eventInfo.name = 'security arm away';
76 | eventInfo.text = 'Bitdog security armed, set for away mode';
77 | publish(eventInfo);
78 | };
79 |
80 | this.publishSecurityArmStay = function () {
81 | var eventInfo = new EventInfo();
82 | eventInfo.name = 'security arm stay';
83 | eventInfo.text = 'Bitdog security armed, set for stay mode';
84 | publish(eventInfo);
85 | };
86 |
87 | this.publishSecurityDisarmed = function () {
88 | var eventInfo = new EventInfo();
89 | eventInfo.name = 'security disarmed';
90 | eventInfo.text = 'Bitdog security has been disarmed';
91 | publish(eventInfo);
92 | };
93 |
94 | this.publishZWaveAddNode = function (zwaveNode) {
95 | var eventInfo = new EventInfo();
96 | eventInfo.name = 'zwave add node';
97 | eventInfo.text = 'Added ZWave device, ' + zwaveNode.displayName;
98 | eventInfo.zwaveNode = zwaveNode;
99 | publish(eventInfo);
100 | };
101 |
102 | this.publishZWaveRemoveNode = function (zwaveNode) {
103 | var eventInfo = new EventInfo();
104 | eventInfo.name = 'zwave remove node';
105 | eventInfo.text = 'Removed ZWave device, ' + zwaveNode.displayName;
106 | eventInfo.zwaveNode = zwaveNode;
107 | publish(eventInfo);
108 | };
109 | }
110 |
111 | module.exports = SystemEvents;
--------------------------------------------------------------------------------
/lib/extensionBase.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // extensionBase.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | function ExtensionBase() {
28 |
29 |
30 | }
31 |
32 | ExtensionBase.prototype._bitdogHub = null;
33 |
34 | ExtensionBase.prototype.__defineGetter__('bitdogHub', function () { return this._bitdogHub; });
35 |
36 | ExtensionBase.prototype.__defineSetter__('bitdogHub', function (value) {
37 | var self = this;
38 | this._bitdogHub = value;
39 |
40 | this._bitdogHub.on('message', function (message, configuration, logger) {
41 | self.processMessage(message, configuration, logger);
42 | });
43 |
44 | this._bitdogHub.on('system event', function (eventInfo, configuration, logger) {
45 | self.processSystemEvent(eventInfo, configuration, logger);
46 | });
47 | });
48 |
49 | ExtensionBase.prototype.__defineGetter__('configuration', function () { return this._bitdogHub.bitdogClient.configuration; });
50 |
51 | ExtensionBase.prototype.__defineGetter__('constants', function () { return this._bitdogHub.bitdogClient.constants; });
52 |
53 |
54 | ExtensionBase.prototype.onInitialize = function (configuration, logger) {
55 | };
56 |
57 | ExtensionBase.prototype.onMessage = function (message, configuration, logger) {
58 | };
59 |
60 | ExtensionBase.prototype.onSystemEvent = function (eventInfo, configuration, logger) {
61 | };
62 |
63 | ExtensionBase.prototype.processMessage = function (message, configuration, logger) {
64 | try {
65 | this.onMessage(message, configuration, logger);
66 | }
67 | catch (error) {
68 | logger.logProcessEvent('Bitdog Hub', 'Process message exception: ', error);
69 | }
70 | };
71 |
72 | ExtensionBase.prototype.processSystemEvent = function (eventInfo, configuration, logger) {
73 | try {
74 | this.onSystemEvent(eventInfo, configuration, logger);
75 | }
76 | catch (error) {
77 | logger.logProcessEvent('Bitdog Hub', 'Process system event exception: ', error);
78 | }
79 | };
80 |
81 | ExtensionBase.prototype.addCommand = function (name, messageSchema, executeCallback, startCallback, stopCallback) {
82 | return this.bitdogHub.bitdogClient.addCommand(name, messageSchema, executeCallback, startCallback, stopCallback, false);
83 | };
84 |
85 | ExtensionBase.prototype.addDataCollector = function (name, messageSchema, intervalMilliseconds, collectCallback) {
86 | return this.bitdogHub.bitdogClient.addDataCollector(name, messageSchema, intervalMilliseconds, collectCallback, false);
87 | };
88 |
89 | ExtensionBase.prototype.addData = function (name, messageSchema) {
90 | return this.bitdogHub.bitdogClient.addData(name, messageSchema, false);
91 | };
92 |
93 |
94 | ExtensionBase.prototype.createMessageSchema = function (name) {
95 | return this.bitdogHub.bitdogClient.createMessageSchema(name);
96 | };
97 |
98 | ExtensionBase.prototype.sendData = function (name, messageSchema, callback) {
99 | return this.bitdogHub.bitdogClient.sendData(name, messageSchema, callback);
100 | };
101 |
102 | ExtensionBase.prototype.sendIFTTTCommand = function (appId, name, callback) {
103 | return this._bitdogHub.bitdogClient.sendIFTTTCommand(appId, name, callback);
104 | };
105 |
106 |
107 | module.exports = ExtensionBase;
--------------------------------------------------------------------------------
/lib/ipcManager.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // ipcManager.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | var http = require('http');
27 | var bitdogClient = require('bitdog-client');
28 | var constants = require('./constants.js');
29 | var path = require('path');
30 | var coreMessageSchemas = require('./coreMessageSchemas.js');
31 |
32 | _httpServer = null;
33 | _isRunning = false;
34 | _ipcPort = bitdogClient.configuration.get(constants.IPC_PORT);
35 |
36 | function IPCManager() {
37 |
38 |
39 | }
40 |
41 | IPCManager.prototype.start = function () {
42 | if (_isRunning === false) {
43 | _isRunning = true;
44 | startHttpServer();
45 | }
46 | };
47 |
48 | IPCManager.prototype.stop = function () {
49 | if (_isRunning === true) {
50 | _isRunning = false;
51 |
52 | if (_httpServer !== null)
53 | _httpServer.close();
54 | }
55 | }
56 |
57 | function startHttpServer() {
58 | var ipcPort = bitdogClient.configuration.get(constants.IPC_PORT);
59 |
60 | if (ipcPort !== typeof undefined || ipcPort === null)
61 | ipcPort = 9001;
62 |
63 | _httpServer = http.createServer(function (req, res) {
64 | var message = '';
65 |
66 | req.on('data', function (data) {
67 | message += data;
68 | });
69 |
70 | req.on('end', function () {
71 | var result = false;
72 | try {
73 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_IPC_MANAGER, 'Received IPC message', message);
74 | message = JSON.parse(message);
75 | processIPCMessage(message);
76 | result = true;
77 | }
78 | catch (error) {
79 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_IPC_MANAGER, 'Could not parse IPC message', error);
80 | }
81 |
82 |
83 | res.setHeader('Content-Type', 'application/json');
84 | res.end(JSON.stringify({ result: result }));
85 | });
86 |
87 |
88 | }).listen(_ipcPort, '127.0.0.1', function () {
89 | var address = _httpServer.address().address;
90 | var port = _httpServer.address().port;
91 |
92 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_IPC_MANAGER, 'IPC HTTP listener ready', { host: address, port: port });
93 |
94 | });
95 |
96 | _httpServer.on('close', function () {
97 |
98 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_IPC_MANAGER, 'IPC HTTP listener stopped');
99 |
100 | });
101 | }
102 |
103 | function processIPCMessage(message) {
104 |
105 | switch (message.name) {
106 | case 'motion-event-start':
107 | bitdogClient.sendData('bd-videoMotionEventStart', coreMessageSchemas.videoMotionEventStartMessageSchema, function (newMessage) {
108 | });
109 | break;
110 | case 'motion-event-end':
111 | bitdogClient.sendData('bd-videoMotionEventEnd', coreMessageSchemas.videoMotionEventEndMessageSchema, function (newMessage) {
112 | });
113 | break;
114 | case 'motion-image-captured':
115 | bitdogClient.sendData('bd-videoMotionImageCaptured', coreMessageSchemas.videoMotionImageCapturedMessageSchema, function (newMessage) {
116 | newMessage.imageFileName = path.basename(message.imagePath);
117 | });
118 | break;
119 | default:
120 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_IPC_MANAGER, 'IPC message invalid', message);
121 | break;
122 | }
123 |
124 | }
125 |
126 | module.exports = new IPCManager();
--------------------------------------------------------------------------------
/lib/zwave/zwaveCommandClasses.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zwaveCommandClasses.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | function ZWaveCommandClasses() {
27 | var commandClasses = {
28 | 'No Operation': 0,
29 | 'Basic': 32,
30 | 'Controller Replication': 33,
31 | 'Application Status': 34,
32 | 'ZIP Services': 35,
33 | 'ZIP Server': 36,
34 | 'Switch Binary': 37,
35 | 'Switch Multilevel': 38,
36 | 'Switch All': 39,
37 | 'Switch Toggle Binary': 40,
38 | 'Switch Toggle Multilevel': 41,
39 | 'Chimney Fan': 42,
40 | 'Scene Activation': 43,
41 | 'Scene Actuator Configuration': 44,
42 | 'Scene Controller Configuration': 45,
43 | 'ZIP Client': 46,
44 | 'ZIP Advanced Services': 47,
45 | 'Sensor Binary': 48,
46 | 'Sensor Multilevel': 49,
47 | 'Meter': 50,
48 | 'Switch Color': 51,
49 | 'Network Management Inclusion': 52,
50 | 'Meter Pulse': 53,
51 | 'Meter Tbl Config': 60,
52 | 'Meter Tbl Monitor': 61,
53 | 'Meter Tbl Push': 62,
54 | 'Thermostat Heating': 56,
55 | 'Thermostat Mode': 64,
56 | 'Thermostat Operating State': 66,
57 | 'Thermostat Setpoint': 67,
58 | 'Thermostat Fan Mode': 68,
59 | 'Thermostat Fan State': 69,
60 | 'Climate Control Schedule': 70,
61 | 'Thermostat Setback': 71,
62 | 'Door Lock Logging': 76,
63 | 'Schedule Entry Lock': 78,
64 | 'Basic Window Covering': 80,
65 | 'MTP Window Covering': 81,
66 | 'Association Grp Info': 89,
67 | 'Device Reset Locally': 90,
68 | 'Central Scene': 91,
69 | 'IP Association': 92,
70 | 'Antitheft': 93,
71 | 'ZwavePlus Info': 94,
72 | 'Multi Instance': 96,
73 | 'Door Lock': 98,
74 | 'User Code': 99,
75 | 'Barrier Operator': 102,
76 | 'Configuration': 112,
77 | 'Alarm': 113,
78 | 'Manufacturer Specific': 114,
79 | 'Powerlevel': 115,
80 | 'Protection': 117,
81 | 'Lock': 118,
82 | 'Node Naming': 119,
83 | 'Firmware Update MD': 122,
84 | 'Grouping Name': 123,
85 | 'Remote Association Activate': 124,
86 | 'Remote Association': 125,
87 | 'Battery': 128,
88 | 'CLock': 129,
89 | 'Hail': 130,
90 | 'Wake Up': 132,
91 | 'Association': 133,
92 | 'Version': 134,
93 | 'Indicator': 135,
94 | 'Proprietary': 136,
95 | 'Language': 137,
96 | 'Time': 138,
97 | 'Time ParaMeters': 139,
98 | 'Geographic Location': 140,
99 | 'Composite': 141,
100 | 'Multi Instance Association': 142,
101 | 'Multi CMD': 143,
102 | 'Energy Production': 144,
103 | 'Manufacturer Proprietary': 145,
104 | 'Screen MD': 146,
105 | 'Screen Attributes': 147,
106 | 'Simple AV Control': 148,
107 | 'AV Content Directory MD': 149,
108 | 'AV Renderer Status': 150,
109 | 'AV Content Search MD': 151,
110 | 'Security': 152,
111 | 'AV Tagging MD': 153,
112 | 'IP Configuration': 154,
113 | 'Association Command Configuration': 155,
114 | 'Alarm Sensor': 156,
115 | 'Alarm Silence': 157,
116 | 'Sensor Configuration': 158,
117 | 'Mark': 239,
118 | 'Non Interoperable': 240
119 | };
120 |
121 | this.getCommand = function (number) {
122 | for (var propertyName in commandClasses) {
123 | if (commandClasses[propertyName] == number)
124 | return propertyName;
125 | }
126 |
127 | return number.toString();
128 | };
129 | }
130 |
131 | module.exports = new ZWaveCommandClasses();
--------------------------------------------------------------------------------
/extensions/IFTTTExtension.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // IFTTTExtension.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | // Extension will inherit functions from ExtensionBase
28 | // Make sure the path to extensionBase is correct
29 | var ExtensionBase = require('../lib/extensionBase.js');
30 | var util = require('util');
31 |
32 | // Example Raspberry PI I/O library
33 | var rpio = require('rpio');
34 |
35 | var API_KEY = 'test';
36 | var ledPin = 11; // hardware pin 11
37 | var buttonPin = 13; // hardware pin 13
38 |
39 | var blinkTimer = null;
40 |
41 | // Initialize a variable to hold button state
42 | var buttonState = 'unknown';
43 |
44 | // By default the rpio module will use /dev/gpiomem
45 | // when using simple GPIO access.
46 | // To access this device, your user will
47 | // need to be a member of the gpio group,
48 | // and you may need to configure udev with the following rule (as root):
49 |
50 | //$ cat >/etc/udev/rules.d/20-gpiomem.rules << EOF
51 | //SUBSYSTEM=="bcm2835-gpiomem", KERNEL=="gpiomem", GROUP="gpio", MODE="0660"
52 | //EOF
53 |
54 | // Create a class called Extension
55 | function Extension() {
56 |
57 | }
58 |
59 | // Extension inherits from ExtensionBase
60 | util.inherits(Extension, ExtensionBase);
61 |
62 | // Messages from and to this hub will pass through this function.
63 | // A good spot to watch for Z-Wave messages
64 | Extension.prototype.onMessage = function (message, configuration, logger) {
65 |
66 | // Messages will go through here, check them and do something.
67 | //logger.log('User', 'Got message and handling', message);
68 |
69 | };
70 |
71 | // This function will be called once during initialization.
72 | // Setup command and data capture here.
73 | Extension.prototype.onInitialize = function (configuration, logger) {
74 | var self = this;
75 |
76 | var options = {
77 | gpiomem: true, /* Use /dev/gpiomem */
78 | mapping: 'physical', /* Use the P1-P40 numbering scheme */
79 | };
80 |
81 | rpio.init(options);
82 |
83 |
84 | // Create a custom message schema with one string property.
85 | var onOffMessageSchema = this.createMessageSchema('OnOff')
86 | .addStringProperty('value1', 'off', { values: ['on', 'off'] });
87 |
88 | // Open a GPIO pin for our LED, initialize to off.
89 | rpio.open(ledPin, rpio.OUTPUT, rpio.HIGH);
90 | // Open a GPIO pin for our switch
91 | rpio.open(buttonPin, rpio.INPUT, rpio.PULL_DOWN);
92 |
93 | // Create a callback function for the rpio polling routine
94 | function pollcb(pin) {
95 | // Read the state of the switch pin
96 | var newState = rpio.read(pin) ? 'on' : 'off';
97 |
98 | // If the switch pin has transitioned to a new value...
99 | if (newState !== buttonState) {
100 | // Set the variable
101 | buttonState = newState;
102 |
103 | // Send a message to our IFTTT cloud account about our new switch state.
104 | self.sendIFTTTCommand(API_KEY,'Switch Status', function (message) {
105 | message.value1 = buttonState;
106 | });
107 | }
108 | }
109 |
110 | // The the rpio library to poll a pin
111 | rpio.poll(buttonPin, pollcb);
112 |
113 | // Add a command to this hub that turns the LED on and off
114 | this.addCommand('Turn LED on/off', onOffMessageSchema, function (message, configuration, logger) {
115 |
116 | // check if we already have a timer running
117 | if (blinkTimer === null) {
118 |
119 | // turn the LED on by setting pin low
120 | rpio.write(ledPin, rpio.LOW);
121 |
122 | // turn off LED after 30 seconds
123 | blinkTimer = setTimeout(function () {
124 | rpio.write(ledPin, rpio.HIGH);
125 | blinkTimer = null;
126 | }, 30000);
127 | }
128 |
129 | });
130 |
131 |
132 | };
133 |
134 | // Export your Extension class so it can be loaded by the framework
135 | module.exports = Extension;
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // main.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | var bitdogHub = require('./lib/bitdogHub.js');
27 | var bitdogClient = require('bitdog-client');
28 | var program = require('commander');
29 | var path = require('path');
30 | var constants = require('./lib/constants.js');
31 | var savedExtensionPaths = bitdogClient.configuration.get(constants.EXTENSION_PATHS);
32 |
33 | if (typeof savedExtensionPaths === typeof undefined || savedExtensionPaths === null)
34 | savedExtensionPaths = [];
35 |
36 | // Create serializable error objects
37 | if (!('toJSON' in Error.prototype)) {
38 | Object.defineProperty(Error.prototype, 'toJSON', {
39 | value: function () {
40 | var alt = {};
41 |
42 | Object.getOwnPropertyNames(this).forEach(function (key) {
43 | alt[key] = this[key];
44 | }, this);
45 |
46 | return alt;
47 | },
48 | configurable: true,
49 | writable: true
50 | });
51 | }
52 |
53 | process.on('SIGINT', function () {
54 | setTimeout(function () {
55 | bitdogClient.logger.logProcessEvent('Bitdog Hub', 'Calling process exit...');
56 | process.exit(0);
57 | }, 10000);
58 |
59 | bitdogClient.logger.logProcessEvent('Bitdog Hub', 'SIGINT, stopping.');
60 |
61 | bitdogHub.stop();
62 |
63 | });
64 |
65 | process.on('uncaughtException', function (error) {
66 | bitdogClient.logger.logProcessEvent('Bitdog Hub', 'Unhandled exception: ' , error);
67 | process.kill(process.pid, 'SIGINT');
68 | });
69 |
70 | program
71 | .version('2.0.01')
72 | .description('Bitdog Hub')
73 | .option('-l,--logpath ', 'The direcotry for log files.')
74 | .option('-c,--configpath ', 'The directory for configuration files.')
75 | .option('-t,--tail', 'Write logs to console also.')
76 | .option('-e,--extension ', 'Path to file that has extension code. Use clear to remote extension from stored configuration.');
77 |
78 |
79 | program.parse(process.argv);
80 |
81 | if (typeof program.tail === typeof undefined) {
82 | bitdogClient.configuration.logToConsole = false;
83 | } else {
84 | bitdogClient.configuration.logToConsole = true;
85 | }
86 |
87 | if (typeof program.logpath !== typeof undefined) {
88 | var logFilePath = path.resolve(program.logpath, bitdogClient.constants.LOG_FILE_NAME);
89 | bitdogClient.configuration.logFilePath = logFilePath;
90 | }
91 |
92 | console.log("Configuration file path is " + bitdogClient.configuration.configFilePath);
93 | console.log("Logging to " + bitdogClient.configuration.logFilePath);
94 |
95 |
96 | if (typeof program.extension !== typeof undefined) {
97 |
98 | if (program.extension === 'clear') {
99 | savedExtensionPaths = [];
100 | bitdogClient.configuration.set(constants.EXTENSION_PATHS, savedExtensionPaths);
101 | }
102 | else {
103 | saveExtension(path.resolve(program.extension));
104 | }
105 | }
106 |
107 | loadExtensions();
108 |
109 | bitdogHub.start();
110 |
111 | function saveExtension(extensionFilePath) {
112 | savedExtensionPaths.push(extensionFilePath);
113 | bitdogClient.configuration.set(constants.EXTENSION_PATHS, savedExtensionPaths);
114 | }
115 |
116 | function loadExtensions() {
117 | //process.chdir(__dirname);
118 | //console.log("Setting working directory to " + __dirname);
119 | var extensionFilePath = '';
120 |
121 | for (var index = 0; index < savedExtensionPaths.length; index++) {
122 | extensionFilePath = savedExtensionPaths[index];
123 | console.log("Loading extension at " + extensionFilePath);
124 |
125 | try {
126 | var Extension = require(extensionFilePath);
127 |
128 | var extension = new Extension();
129 | extension.bitdogHub = bitdogHub;
130 |
131 | extension.onInitialize(bitdogClient.configuration, bitdogClient.logger);
132 |
133 | }
134 | catch (exception) {
135 | bitdogClient.logger.logProcessEvent('Bitdog Hub', 'Exception loading extension: ', { message: exception.message, stack: exception.stack });
136 | }
137 | }
138 | }
139 |
140 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/extensions/rpioExtension.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // rpioExtension.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | // Extension will inherit functions from ExtensionBase
28 | // Make sure the path to extensionBase is correct
29 | var ExtensionBase = require('../lib/extensionBase.js');
30 | var util = require('util');
31 |
32 | // Example Raspberry PI I/O library
33 | var rpio = require('rpio');
34 |
35 | // By default the rpio module will use /dev/gpiomem
36 | // when using simple GPIO access.
37 | // To access this device, your user will
38 | // need to be a member of the gpio group,
39 | // and you may need to configure udev with the following rule (as root):
40 |
41 | //$ cat >/etc/udev/rules.d/20-gpiomem.rules << EOF
42 | //SUBSYSTEM=="bcm2835-gpiomem", KERNEL=="gpiomem", GROUP="gpio", MODE="0660"
43 | //EOF
44 |
45 | // Create a class called Extension
46 | // This can be any name, give it a good one.
47 | function Extension() {
48 | // Initialize a variable to hold button state
49 | this.buttonState = 'unknown';
50 | }
51 |
52 | // Extension inherits from ExtensionBase
53 | util.inherits(Extension, ExtensionBase);
54 |
55 | // Messages from and to this hub will pass through this function.
56 | // A good spot to watch for Z-Wave messages
57 | Extension.prototype.onMessage = function (message, configuration, logger) {
58 |
59 | // Messages will go through here, check them and do something.
60 | //logger.log('User', 'Got message and handling', message);
61 |
62 | };
63 |
64 | // This function will be called once during initialization.
65 | // Setup command and data capture here.
66 | Extension.prototype.onInitialize = function (configuration, logger) {
67 | var self = this;
68 | var ledPin = 35;
69 | var buttonPin = 37;
70 |
71 | var options = {
72 | gpiomem: true, /* Use /dev/gpiomem */
73 | mapping: 'physical', /* Use the P1-P40 numbering scheme */
74 | };
75 |
76 | rpio.init(options);
77 |
78 |
79 | // Create a custom message schema with one string property.
80 | var onOffMessageSchema = this.createMessageSchema('OnOff')
81 | .addStringProperty('value', 'off', { values: ['on', 'off'] });
82 |
83 | // Open a GPIO pin for our LED, initialize to off.
84 | rpio.open(ledPin, rpio.OUTPUT, rpio.LOW);
85 | // Open a GPIO pin for our switch
86 | rpio.open(buttonPin, rpio.INPUT, rpio.PULL_DOWN);
87 |
88 | // Create a callback function for the rpio polling routine
89 | function pollcb(pin) {
90 | // Read the state of the switch pin
91 | var newState = rpio.read(pin) ? 'on' : 'off';
92 |
93 | // If the switch pin has transitioned to a new value...
94 | if (newState !== self.buttonState) {
95 | // Set the variable
96 | self.buttonState = newState;
97 |
98 | // Send a message to the cloud about our new switch state.
99 | this.sendData('Switch Status', onOffMessageSchema, function (message) {
100 | message.value = self.buttonState;
101 | });
102 | }
103 | }
104 |
105 | // The the rpio library to poll a pin
106 | // Just an example way to do it.
107 | rpio.poll(buttonPin, pollcb);
108 |
109 | // Add a command to this hub that turns the LED on and off
110 | this.addCommand('Turn LED on/off', onOffMessageSchema, function (message, configuration, logger) {
111 |
112 | // If the message contains 'off' set the GPIO pin high - depends on how the LED is wired to the GPIO pins
113 | if (message.value === 'off') {
114 | rpio.write(ledPin, rpio.HIGH);
115 | } else {
116 | // Or turn on the LED by setting the pin low.
117 | rpio.write(ledPin, rpio.LOW);
118 | }
119 |
120 | });
121 |
122 | // Register data collector and set it to poll every 60 seconds.
123 | // Set seconds to -1 to not poll at all.
124 | this.addDataCollector('Switch Status', onOffMessageSchema, 60000, function (message, configuration, logger) {
125 |
126 | // Read the state of the switch pin
127 | self.buttonState = rpio.read(buttonPin) ? 'on' : 'off';
128 |
129 | message.value = self.buttonState;
130 | });
131 | };
132 |
133 | // Export your Extension class so it can be loaded by the framework
134 | module.exports = Extension;
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/BitdogHub.njsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 11.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
6 | BitdogHub
7 | BitdogSA
8 |
9 |
10 |
11 | Debug
12 | 2.0
13 | 38f4cfe3-f058-4502-a3ac-88a177bce85c
14 |
15 |
16 | lib\bitdogSA.js
17 | False
18 |
19 |
20 | .
21 | .
22 | v4.0
23 | {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}
24 | ShowAllFiles
25 | false
26 |
27 |
28 | true
29 |
30 |
31 | true
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Code
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/lib/automation/bitdogAutomation.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // bitdogAutomation.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 | 'use strict';
26 |
27 | let EventProcessor = require('../eventProcessor.js').EventProcessor;
28 | let Scheduler = require('./scheduler.js');
29 | let EventCapturer = require('./eventCapturer.js');
30 | let util = require('util');
31 | let bitdogClient = require('bitdog-client');
32 | let constants = require('../constants.js');
33 | let coreMessageSchemas = require('../coreMessageSchemas.js');
34 |
35 | function BitdogAutomation() {
36 |
37 |
38 | let _bitdogZWave = null;
39 | let _automationConfiguration = [];
40 | let _isRunning = false;
41 | let _timer = null;
42 | let _weatherTimer = null;
43 | let _scheduler = null;
44 | let _eventCapturer = null;
45 |
46 | // Pass in the external zwave controller instance so that automation can send its own commands
47 | this.__defineGetter__('bitdogZWave', function () { return _bitdogZWave; });
48 | this.__defineSetter__('bitdogZWave', function (value) { _bitdogZWave = value; });
49 |
50 | this.__defineGetter__('automationConfiguration', function () { return _automationConfiguration; });
51 | this.__defineSetter__('automationConfiguration', function (value) { _automationConfiguration = value; });
52 |
53 | this.__defineGetter__('isRunning', function () { return _isRunning; });
54 | this.__defineSetter__('isRunning', function (value) { _isRunning = value; });
55 |
56 | this.__defineGetter__('scheduler', function () { return _scheduler; });
57 | this.__defineSetter__('scheduler', function (value) { _scheduler = value; });
58 |
59 | this.__defineGetter__('eventCapturer', function () { return _eventCapturer; });
60 | this.__defineSetter__('eventCapturer', function (value) { _eventCapturer = value; });
61 |
62 | this.__defineGetter__('timer', function () { return _timer; });
63 | this.__defineSetter__('timer', function (value) { _timer = value; });
64 |
65 | this.__defineGetter__('weatherTimer', function () { return _weatherTimer; });
66 | this.__defineSetter__('weatherTimer', function (value) { _weatherTimer = value; });
67 |
68 |
69 | }
70 |
71 | util.inherits(BitdogAutomation, EventProcessor);
72 |
73 | BitdogAutomation.prototype.tock = function () {
74 | if (this.isRunning === true && typeof this.scheduler !== typeof undefined && this.scheduler !== null) {
75 | //bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Tock');
76 | try {
77 | this.scheduler.tock();
78 | } catch (error) {
79 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Exception', error);
80 | }
81 | }
82 | }
83 |
84 | BitdogAutomation.prototype.weatherTock = function () {
85 | if (this.isRunning === true && typeof this.scheduler !== typeof undefined && this.scheduler !== null) {
86 | //bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Tock');
87 | try {
88 | this.scheduler.weatherTock();
89 | } catch (error) {
90 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Exception', error);
91 | }
92 | }
93 | }
94 |
95 | BitdogAutomation.prototype.onProcessMessage = function (message) {
96 | if (this.isRunning === true && typeof this.eventCapturer !== typeof undefined && this.eventCapturer !== null) {
97 | try {
98 | this.eventCapturer.onProcessMessage(message);
99 | } catch (error) {
100 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Exception', error);
101 | }
102 | }
103 | }
104 |
105 | BitdogAutomation.prototype.stop = function () {
106 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Stopping....');
107 | clearInterval(this.timer);
108 | clearInterval(this.weatherTimer);
109 | this.isRunning = false;
110 |
111 | }
112 |
113 | BitdogAutomation.prototype.getConfiguration = function () {
114 | let configuration = bitdogClient.configuration.get(constants.AUTOMATIONS_CONFIG);
115 |
116 | if (typeof configuration === typeof undefined || configuration === null)
117 | this.automationConfiguration = [];
118 | else
119 | this.automationConfiguration = configuration;
120 | }
121 |
122 | BitdogAutomation.prototype.start = function () {
123 |
124 | if (this.isRunning === false) {
125 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Starting....');
126 | this.getConfiguration();
127 |
128 | this.createScheduler();
129 | this.createEventCapturer();
130 | this.isRunning = true;
131 |
132 | this.timer = setInterval(function () { this.tock(); }.bind(this), 30000); // 30 second tick-tock
133 | this.weatherTimer = setInterval(function () { this.weatherTock(); }.bind(this), 1000 * 60 * 60); // Get weather update one hour tick-tock
134 |
135 | setTimeout(function () { this.weatherTock(); }.bind(this), 1000); // Get first weather update now
136 | }
137 |
138 | }
139 |
140 | BitdogAutomation.prototype.restart = function () {
141 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Restarting....');
142 |
143 | if (this.isRunning === true) {
144 | this.stop();
145 | }
146 |
147 | this.start();
148 | }
149 |
150 | BitdogAutomation.prototype.createScheduler = function () {
151 | this.scheduler = new Scheduler(this.automationConfiguration);
152 |
153 | }
154 |
155 | BitdogAutomation.prototype.createEventCapturer = function () {
156 | this.eventCapturer = new EventCapturer(this.automationConfiguration);
157 |
158 | }
159 |
160 | module.exports = new BitdogAutomation();
161 |
--------------------------------------------------------------------------------
/lib/cameras/websocketsProcess.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // websocketsProcess.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | // Code for this file was inspired by project http://drejkim.com/projects/edi-cam/
25 | //-----------------------------------------------------------------------------
26 | 'use strict';
27 |
28 | let http = require('http');
29 | let ws = require('ws');;
30 |
31 | let _wsClientOpen = false;
32 | let _wsClient = null;
33 | let _httpServer = null;
34 | let _isRunning = false;
35 | let _url = '';
36 | let _nodeId = '';
37 | let _authKey = '';
38 | let _videoStreamerPort = 9000;
39 | let _enableStream = false;
40 | let _restartTimeout = null;
41 |
42 | process.on('message', function (message) {
43 | if (typeof message != typeof undefined && typeof message.name != typeof undefined && message.name != null) {
44 | switch (message.name) {
45 | case 'start':
46 | start(message);
47 | break;
48 | case 'stop':
49 | stop(message);
50 | break;
51 | }
52 | }
53 | });
54 |
55 | function start(message) {
56 |
57 | if (_restartTimeout !== null)
58 | clearTimeout(_restartTimeout);
59 |
60 | if (_isRunning === false) {
61 | _isRunning = true;
62 |
63 | _url = message.url;
64 | _nodeId = message.nodeId;
65 | _authKey = message.authKey;
66 | _enableStream = false;
67 |
68 | if (typeof message.videoStreamerPort !== typeof undefined)
69 | _videoStreamerPort = message.videoStreamerPort;
70 |
71 | startWebSocket();
72 | startHttpServer();
73 | }
74 | }
75 |
76 | function stop(message) {
77 |
78 | if (_isRunning === true) {
79 | _isRunning = false;
80 | _enableStream = false;
81 |
82 | if (_wsClient.readyState === ws.OPEN) {
83 | _wsClientOpen = false;
84 | _wsClient.close();
85 | }
86 |
87 | if (_httpServer !== null)
88 | _httpServer.close();
89 | }
90 | }
91 |
92 | function startWebSocket() {
93 |
94 |
95 | _wsClient = new ws(_url, { headers: { node_id: _nodeId, auth_key: _authKey } });
96 |
97 | _wsClient.on('open', function () {
98 | _wsClientOpen = true;
99 | process.send({ name: 'ws-connection-ready' });
100 |
101 | });
102 |
103 | _wsClient.on('message', function (data) {
104 |
105 | try {
106 |
107 | data = JSON.parse(data);
108 |
109 | process.send({ name: 'ws-connection-data', data: data });
110 |
111 | switch (data.name) {
112 | case 'clientCount':
113 | _enableStream = data.count > 0;
114 | process.send({ name: 'ws-connection-sending-video', data: { enableStream: _enableStream } });
115 | break;
116 | default:
117 | process.send({ name: 'ws-connection-error', data: { message: 'unknown message name', name: data.name } });
118 | break;
119 | }
120 |
121 | }
122 | catch (error) {
123 | process.send({ name: 'ws-connection-error', data: { url: _url, error: error, data: data } });
124 | restartWebSocket();
125 | }
126 |
127 | });
128 |
129 | _wsClient.on('close', function () {
130 | process.send({ name: 'ws-connection-lost' });
131 | restartWebSocket();
132 | });
133 |
134 | _wsClient.on('error', function (error) {
135 | process.send({ name: 'ws-connection-error', data: { url: _url, error: error } });
136 | restartWebSocket();
137 | });
138 | }
139 |
140 | function restartWebSocket() {
141 |
142 | process.send({ name: 'ws-connection-retry' });
143 |
144 | _wsClientOpen = false;
145 |
146 | if (_wsClient !== null) {
147 |
148 | try {
149 | if (_wsClient.readyState === ws.OPEN) {
150 | _wsClient.close();
151 | }
152 | }
153 | catch (error) { }
154 |
155 | try {
156 | _wsClient.removeAllListeners('open');
157 | _wsClient.removeAllListeners('message');
158 | _wsClient.removeAllListeners('error');
159 | }
160 | catch (error) { }
161 |
162 | _wsClient = null;
163 | }
164 |
165 |
166 | _restartTimeout = setTimeout(function () {
167 | _restartTimeout = null;
168 |
169 | if (_isRunning === true) {
170 | if (_wsClient === null) {
171 | startWebSocket();
172 | }
173 | } else {
174 | restartWebSocket();
175 | }
176 |
177 | }, 60000);
178 |
179 |
180 |
181 | }
182 |
183 | function startHttpServer() {
184 |
185 | _httpServer = http.createServer(function (req, res) {
186 |
187 | process.send({ name: 'http-connection-connected', host: req.socket.remoteAddress, port: req.socket.remotePort });
188 |
189 | req.on('data', function (data) {
190 | if (_wsClientOpen === true && _enableStream === true) {
191 | try {
192 | _wsClient.send(data, { binary: true });
193 | }
194 | catch (error) {
195 |
196 | }
197 | }
198 | });
199 |
200 | req.on('end', function () {
201 | process.send({ name: 'http-connection-lost' });
202 | res.end();
203 | });
204 |
205 |
206 | }).listen(_videoStreamerPort, '127.0.0.1', function () {
207 | let address = _httpServer.address().address;
208 | let port = _httpServer.address().port;
209 |
210 | process.send({ name: 'http-server-ready', host: address, port: port });
211 | });
212 |
213 | _httpServer.on('close', function () {
214 |
215 | process.send({ name: 'http-server-stopped' });
216 |
217 | });
218 | }
219 |
220 |
221 |
222 |
--------------------------------------------------------------------------------
/lib/cameras/videoStreamer.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // videoStreamer.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | // Code for this file was inspired by project http://drejkim.com/projects/edi-cam/
25 | //-----------------------------------------------------------------------------
26 | 'use strict';
27 |
28 | // modules
29 | let childProcess = require('child_process');
30 | let EventEmitter = require('events').EventEmitter;
31 | let util = require('util');
32 | let path = require('path');
33 | let url = require('url');
34 |
35 | let bitdogClient = require('bitdog-client');
36 | let constants = require('../constants.js');
37 | let websocketsProcessPath = path.resolve(__dirname , './websocketsProcess.js');
38 |
39 |
40 | function VideoStreamer(videoHubUrl, sourcePath) {
41 | let _websocketProcess = null;
42 | let _stopping = false;
43 |
44 |
45 | this.__defineGetter__('stopping', function () { return _stopping; });
46 | this.__defineSetter__('stopping', function (value) { _stopping = value; });
47 |
48 | this.__defineGetter__('source', function () { return sourcePath; });
49 |
50 | this.__defineGetter__('url', function () { return videoHubUrl; });
51 |
52 | this.__defineGetter__('websocketProcess', function () { return _websocketProcess; });
53 | this.__defineSetter__('websocketProcess', function (value) { _websocketProcess = value; });
54 |
55 | }
56 |
57 | util.inherits(VideoStreamer, EventEmitter);
58 |
59 | VideoStreamer.prototype.start = function () {
60 | let self = this;
61 |
62 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'Starting websocket streamer to Bitdog Cloud for ' + this.source);
63 |
64 | this.websocketProcess = childProcess.fork(websocketsProcessPath, [], { execArgv: [], cwd: process.cwd(), silent: true });
65 |
66 | this.websocketProcess.stdout.on("data", function (data) {
67 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, data);
68 | });
69 |
70 | this.websocketProcess.stderr.on("data", function (data) {
71 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, data);
72 | });
73 |
74 | this.websocketProcess.on('error', function (error) {
75 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'Websocket streamer error', error);
76 | });
77 |
78 | this.websocketProcess.on('message', function (message) {
79 |
80 | if (typeof message != typeof undefined && typeof message.name != typeof undefined && message.name != null) {
81 |
82 |
83 | switch (message.name) {
84 | case 'http-server-ready': {
85 | let url = 'http://' + message.host + ':' + message.port;
86 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'Local HTTP server ready for video', url);
87 | }
88 | break;
89 | case 'http-server-stopped': {
90 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'Local HTTP server stopped for video');
91 | }
92 | break;
93 | case 'http-connection-lost':
94 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'Local HTTP connection lost for video');
95 | break;
96 | case 'http-connection-connected':
97 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'Local HTTP connected for video', message);
98 | break;
99 | case 'ws-connection-lost':
100 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process connection lost for video');
101 | break;
102 | case 'ws-connection-ready':
103 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process connection ready for video');
104 | break;
105 | case 'ws-connection-retry':
106 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process connection reconecting for video');
107 | break;
108 | case 'ws-connection-error':
109 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process connection error', message.data);
110 | break;
111 | case 'ws-connection-data':
112 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process connection data message', message.data);
113 | break;
114 | case 'ws-connection-sending-video':
115 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process sending video', message.data);
116 | break;
117 | default:
118 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process unknown message', message);
119 | break;
120 |
121 | }
122 | }
123 |
124 | });
125 |
126 | this.websocketProcess.on('disconnected', function () {
127 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'websocket process disconnected');
128 | });
129 |
130 | this.websocketProcess.send({
131 | name: 'start',
132 | source: this.source,
133 | url: this.url + '/source/' + encodeURI(this.source),
134 | nodeId: bitdogClient.configuration.nodeId,
135 | authKey: bitdogClient.configuration.authKey,
136 | videoStreamerPort: bitdogClient.configuration.get(constants.VIDEO_STREAMER_PORT)
137 | });
138 |
139 | }
140 |
141 | VideoStreamer.prototype.stop = function () {
142 |
143 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_STREAMER, 'Stopping websocket streamer to Bitdog Cloud for ' + this.source);
144 |
145 | if (this.stopping !== true) {
146 | this.stopping = true;
147 |
148 | this.websocketProcess.send({
149 | name: 'stop'
150 | });
151 | }
152 | };
153 |
154 | module.exports = VideoStreamer;
--------------------------------------------------------------------------------
/lib/constants.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // constants.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 |
28 | function Constants() {
29 | ////////////////// Message Classes /////////////////////
30 | this.MESSAGE_CLASS_ZWAVE_CONFIGURATION = 'zwaveConfiguration';
31 | this.MESSAGE_CLASS_ZWAVE_SCENE_CONFIGURATION = 'zwaveSceneConfiguration';
32 | ////////////////// Zwave Message Schema //////////////////////
33 | this.MESSAGE_SCHEMA_ZWAVE_NODE_STATUS = 'bitdog-zwave-node-status';
34 | this.MESSAGE_SCHEMA_ZWAVE_VALUE = 'bitdog-zwave-value';
35 | this.MESSAGE_SCHEMA_ZWAVE_ENABLE_POLLING = 'bitdog-zwave-enable-polling';
36 | this.MESSAGE_SCHEMA_ZWAVE_DISABLE_POLLING = 'bitdog-zwave-disable-polling';
37 | this.MESSAGE_SCHEMA_ZWAVE_GET_POLLING_INTENSITY = 'bitdog-zwave-get-polling-intensity';
38 | this.MESSAGE_SCHEMA_ZWAVE_GET_POLLING_ENABLED = 'bitdog-zwave-get-polling-enabled';
39 | this.MESSAGE_SCHEMA_ZWAVE_CONFIGURATION = 'bitdog-zwave-configuration';
40 | this.MESSAGE_SCHEMA_ZWAVE_SCENE_CONFIGURATION = 'bitdog-zwave-scene-configuration';
41 | this.MESSAGE_SCHEMA_ZWAVE_SET_NODE = 'bitdog-zwave-set-node';
42 | this.MESSAGE_SCHEMA_ZWAVE_SET_NODE_LEVEL = 'bitdog-zwave-set-node-level';
43 | this.MESSAGE_SCHEMA_ZWAVE_ACTIVATE = 'bitdog-zwave-activate';
44 | this.MESSAGE_SCHEMA_ZWAVE_ADD_NODE = 'bitdog-zwave-add-node';
45 | this.MESSAGE_SCHEMA_ZWAVE_NODE = 'bitdog-zwave-node';
46 | this.MESSAGE_SCHEMA_ZWAVE_CONTROLLER_COMMAND = 'bitdog-zwave-controller-command';
47 | this.MESSAGE_SCHEMA_ZWAVE_HEAL_NETWORK_NODE = 'bitdog-zwave-heal-network-node';
48 | this.MESSAGE_SCHEMA_ZWAVE_RENAME = 'bitdog-zwave-rename';
49 | this.MESSAGE_SCHEMA_ZWAVE_CONTROLLER_MODE = 'bitdog-zwave-controller-mode';
50 |
51 | this.MESSAGE_SCHEMA_ZWAVE_SET_PERCENTAGE = 'bitdog-zwave-set-percentage';
52 | //this.MESSAGE_SCHEMA_ZWAVE_INCREMENT_PERCENTAGE = 'bitdog-zwave-increment-percentage';
53 | //this.MESSAGE_SCHEMA_ZWAVE_DECREMENT_PERCENTAGE = 'bitdog-zwave-decrement-percentage';
54 | this.MESSAGE_SCHEMA_ZWAVE_SET_TEMPERTURE = 'bitdog-zwave-set-temperture';
55 | this.MESSAGE_SCHEMA_ZWAVE_INCREMENT_DECREMENT_TEMPERTURE = 'bitdog-zwave-increment-decrement-temperture';
56 |
57 | this.MESSAGE_SCHEMA_ZWAVE_CREATE_SCENE = 'bitdog-zwave-create-scene';
58 | this.MESSAGE_SCHEMA_ZWAVE_REMOVE_SCENE = 'bitdog-zwave-remove-scene';
59 | this.MESSAGE_SCHEMA_ZWAVE_ADD_SCENE_VALUE = 'bitdog-zwave-add-scene-value';
60 | this.MESSAGE_SCHEMA_ZWAVE_REMOVE_SCENE_VALUE = 'bitdog-zwave-remove-scene-value';
61 | this.MESSAGE_SCHEMA_ZWAVE_GET_SCENE_VALUES = 'bitdog-zwave-get-scene-values';
62 | this.MESSAGE_SCHEMA_ZWAVE_GET_SCENES = 'bitdog-zwave-get-scenes';
63 | this.MESSAGE_SCHEMA_ZWAVE_SCENE_EVENT = 'bitdog-zwave-scene-event';
64 |
65 | //////////////////// Weather Message Schema ///////////////////////////
66 | this.MESSAGE_SCHEMA_WEATHER_REQUEST = 'bitdog-cloud-weather-request';
67 | this.MESSAGE_SCHEMA_WEATHER_FORECAST = 'bitdog-cloud-weather-forecast';
68 |
69 | ////////////////// Alarm Message Schema //////////////////////
70 | this.MESSAGE_SCHEMA_ALARM_ARM_AWAY = 'bitdog-alarm-arm-away';
71 | this.MESSAGE_SCHEMA_ALARM_ARM_STAY = 'bitdog-alarm-arm-stay';
72 | this.MESSAGE_SCHEMA_ALARM_DISARM = 'bitdog-alarm-disarm';
73 | this.MESSAGE_SCHEMA_ALARM_STATUS_CHANGED = 'bitdog-alarm-status-changed';
74 | this.MESSAGE_SCHEMA_ALARM_EVENT = 'bitdog-alarm-event';
75 |
76 | ////////////////// Automation Message Schema //////////////////////
77 | this.MESSAGE_SCHEMA_SAVE_AUTOMATIONS = 'bitdog-save-automation';
78 | this.MESSAGE_SCHEMA_AUTOMATION_EXECUTED = 'bitdog-automation-executed';
79 | this.MESSAGE_SCHEMA_AUTOMATION_SCHEDULED = 'bitdog-automation-scheduled';
80 |
81 | ////////////////// Zone Message Schema //////////////////////
82 | this.MESSAGE_SCHEMA_SAVE_ZONES = 'bitdog-save-zones';
83 | this.MESSAGE_SCHEMA_GET_ZONES = 'bitdog-get-zones';
84 |
85 | ///////////////// GPS Message Schema ///////////////////////
86 | this.MESSAGE_SCHEMA_GPS_LOCATION = 'bitdog-gps-location';
87 |
88 | ///////////////// Video Message Schema ///////////////////////
89 | this.MESSAGE_SCHEMA_VIDEO_SOURCE_SETTINGS = 'bitdog-video-source-settings';
90 | this.MESSAGE_SCHEMA_GET_VIDEO_SOURCES = 'bitdog-get-video-sources';
91 | this.MESSAGE_SCHEMA_START_VIDEO_STREAM = 'bitdog-start-video-stream';
92 | this.MESSAGE_SCHEMA_STOP_VIDEO_STREAM = 'bitdog-stop-video-stream';
93 | this.MESSAGE_SCHEMA_MOTION_EVENT_START = 'bitdog-motion-event-start';
94 | this.MESSAGE_SCHEMA_MOTION_EVENT_END = 'bitdog-motion-event-end';
95 | this.MESSAGE_SCHEMA_MOTION_IMAGE_CAPTURED = 'bitdog-motion-image-captured';
96 |
97 |
98 | ////////////////// Configuration ////////////////////////////
99 | this.ZWAVE_CONNECTIONS_CONFIG = 'zwave:connections';
100 | this.ZONES_CONFIG = 'zone:zones';
101 | this.AUTOMATIONS_CONFIG = 'automation:automations';
102 | this.AUTOMATIONS_LOCATION = 'automation:location';
103 | this.ZWAVE_NETWORKKEY_CONFIG = 'zwave:networkKey';
104 | this.ZWAVE_NODE_INFORMATION = 'zwave:nodeInformation';
105 | this.ZWAVE_POLL_INTERVAL_CONFIG = 'zwave:pollInterval';
106 | this.ZWAVE_INTERVAL_BETWEEN_POLLS_CONFIG = 'zwave:intervalBetweenPolls';
107 |
108 | this.ALARM_NODE = 'alarm:mode';
109 | this.VIDEO_SOURCES = 'video:sources';
110 | this.VIDEO_ENABLED = 'video:enabled';
111 | this.VIDEO_STREAMER_PORT = "video:streamerPort";
112 | this.VIDEO_DVR_PATH = "video:dvrPath";
113 | this.IPC_PORT = "ipc:port";
114 |
115 | ////////////////// Extensions ////////////////////////////////
116 | this.EXTENSION_PATHS = 'extension:paths';
117 |
118 | ////////////////// LOGGING //////////////////////////////////
119 | this.LOG_PROCESS_BITDOG_SA = 'BitdogHub';
120 | this.LOG_PROCESS_ZWAVE = 'ZWave';
121 | this.LOG_PROCESS_BITDOG_CLIENT = 'Bitdog Client';
122 | this.LOG_PROCESS_ALARM = 'Alarm';
123 | this.LOG_PROCESS_BRAIN = 'Brain';
124 | this.LOG_PROCESS_AUTOMATION = 'Automation';
125 | this.LOG_PROCESS_VIDEO_STREAMER = 'Video Streamer';
126 | this.LOG_PROCESS_VIDEO_MANAGER = 'Video Manager';
127 | this.LOG_PROCESS_DVR_MANAGER = 'DVR Manager';
128 | this.LOG_PROCESS_IPC_MANAGER = 'IPC Manager';
129 |
130 | //////////////// CLOUD NODES ////////////////////////////////
131 | this.BITDOG_CLOUD_NODE = "00000000-0000-0000-0000-000000000005"
132 | }
133 |
134 | module.exports = new Constants();
--------------------------------------------------------------------------------
/extensions/sayExtension.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // sayExtension.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | // Extension will inherit functions from ExtensionBase
27 | // Make sure the path to extensionBase is correct
28 | var ExtensionBase = require('../lib/extensionBase.js');
29 | var util = require('util');
30 | var crypto = require('crypto');
31 | var url = require('url');
32 | var https = require('https');
33 | var http = require('http');
34 | var os = require('os');
35 | var fs = require('fs');
36 | var path = require('path');
37 | var child_process = require('child_process');
38 | var sayQueue = [];
39 |
40 |
41 | function Extension() {
42 | this.isPlaying = false;
43 | }
44 | // Extension inherits from ExtensionBase
45 | util.inherits(Extension, ExtensionBase);
46 |
47 | Extension.prototype.onMessage = function (message, configuration, logger) {
48 | };
49 |
50 | Extension.prototype.onInitialize = function (configuration, logger) {
51 | var self = this;
52 |
53 | // Create a custom message schema with one string property.
54 | var playMessageSchema = this.createMessageSchema('Say')
55 | .addStringProperty('text', '', {}, 'The text to play', 'Text');
56 |
57 |
58 | // Add a command to this hub that makes it say the provided text
59 | this.addCommand('Say', playMessageSchema, function (message, configuration, logger) {
60 | self.say(message.text, configuration, logger);
61 |
62 | });
63 |
64 | };
65 |
66 | Extension.prototype.onSystemEvent = function (eventInfo, configuration, logger) {
67 | this.say(eventInfo.text, configuration, logger);
68 | };
69 |
70 | Extension.prototype.say = function (text, configuration, logger) {
71 | sayQueue.push(text);
72 | logger.logProcessEvent('Say extension', 'Enqueued', { text: text });
73 | this.play(configuration, logger);
74 |
75 | };
76 |
77 | Extension.prototype.getAudio = function (text, configuration, logger, successCallback, errorCallback) {
78 |
79 | var self = this;
80 | var port = null;
81 | var protocol = null;
82 | var fileName = crypto.createHash('sha256').update(text).digest('hex') + '.mp3';
83 | var filePath = os.tmpdir() + path.sep + fileName;
84 |
85 | if (fs.existsSync(filePath) === true) {
86 | logger.logProcessEvent('Say extension', 'Found cached file', filePath);
87 |
88 | if (successCallback)
89 | successCallback(filePath);
90 |
91 | return;
92 | }
93 |
94 | var request = {
95 | nodeId: configuration.nodeId,
96 | authKey: configuration.authKey,
97 | text: text
98 | };
99 |
100 | var requestJson = JSON.stringify(request);
101 |
102 | var headers = {
103 | 'Content-Type': 'application/json',
104 | };
105 |
106 | var parsedUrl = url.parse(this.constants.CENTRAL_URL + '/realm/say');
107 |
108 | if (parsedUrl.port != null)
109 | port = parsedUrl.port;
110 | else {
111 | if (parsedUrl.protocol == 'http:')
112 | port = 80;
113 | else (parsedUrl.protocol == 'https:')
114 | port = 443;
115 | }
116 |
117 | var options = {
118 | host: parsedUrl.hostname,
119 | port: port,
120 | path: parsedUrl.pathname,
121 | method: 'POST',
122 | headers: headers
123 | };
124 |
125 | protocol = parsedUrl.protocol == 'https:' ? https : http;
126 |
127 | var request = protocol.request(options, function (response) {
128 | var fileStream = fs.createWriteStream(filePath);
129 | fileStream.on('finish', function () {
130 | fileStream.close(function () {
131 | successCallback(filePath);
132 | }); // close() is async, call cb after close completes.
133 | });
134 |
135 | response.pipe(fileStream);
136 |
137 | });
138 |
139 | request.on('error', function (e) {
140 | if (errorCallback)
141 | errorCallback(e);
142 | });
143 |
144 | request.write(requestJson);
145 | request.end();
146 |
147 | }
148 |
149 | Extension.prototype.play = function (configuration, logger) {
150 | var self = this;
151 |
152 | if (this.isPlaying === true || sayQueue.length < 1)
153 | return;
154 |
155 | this.isPlaying = true;
156 |
157 | var text = sayQueue.shift();
158 |
159 | if (typeof text === typeof undefined || text === null) {
160 | this.isPlaying = false;
161 | return;
162 | }
163 |
164 | this.getAudio(text, configuration, logger,
165 | function (filePath) {
166 |
167 | if (typeof filePath === typeof undefined || filePath === null) {
168 | self.isPlaying = false;
169 | return;
170 | }
171 |
172 | var playerProcess = null;
173 |
174 | try {
175 |
176 | //Found that mplayer may not have correct premissions to play smoothly
177 | // ellevated premissions helps.
178 | playerProcess = child_process.spawn('mplayer', [ '-af', 'volume=10:1', filePath]);
179 |
180 | playerProcess.stdout.on('data', function (data) {
181 | //logger.logProcessEvent(`Say extension`, data);
182 | });
183 |
184 | playerProcess.stderr.on('data', function (data) {
185 | logger.logProcessEvent('Say extension', data);
186 | });
187 |
188 | playerProcess.on('close', function (code) {
189 | self.isPlaying = false;
190 |
191 | if (sayQueue.length > 0) {
192 | setInterval(function () { self.play(configuration, logger); }, 1000);
193 | }
194 |
195 | });
196 |
197 | } catch (error) {
198 | logger.logProcessEvent('Say extension', error);
199 | self.isPlaying = false;
200 |
201 | if (sayQueue.length > 0) {
202 | setInterval(function () { self.play(configuration, logger); }, 1000);
203 | }
204 |
205 | }
206 |
207 | },
208 | function (error) {
209 | logger.logProcessEvent('Say extension', 'Download error ' + error);
210 | self.isPlaying = false;
211 | if (sayQueue.length > 0) {
212 | setInterval(function () { self.play(configuration, logger); }, 1000);
213 | }
214 | });
215 |
216 | }
217 | // Export your Extension class so it can be loaded by the framework
218 | module.exports = Extension;
219 |
220 |
221 |
222 |
--------------------------------------------------------------------------------
/lib/zwave/zwaveNode.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zwaveNode.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | var bitdogClient = require('bitdog-client');
28 | var constants = require('../constants.js');
29 | var ZWaveClass = require('./zwaveClass.js');
30 |
31 | function ZWaveNode(nodeId, zwave) {
32 | var _id = nodeId;
33 | var _manufacturer = '';
34 | var _manufacturerId = '';
35 | var _product = '';
36 | var _productType = '';
37 | var _productId = '';
38 | var _type = '';
39 | var _typeGeneric = '';
40 | var _typeSpecific = '';
41 | var _typeBasic = '';
42 | var _name = '';
43 | var _location = '';
44 | var _classes = [];
45 | var _ready = false;
46 | var _hash = '';
47 | var _status = 'Unknown';
48 | var _neighbors = [];
49 | var _zwave = zwave;
50 |
51 | this.setNodeInformation = function (zwaveNodeInfo, ready) {
52 | _manufacturer = zwaveNodeInfo.manufacturer;
53 | _manufacturerId = zwaveNodeInfo.manufacturerid;
54 | _product = zwaveNodeInfo.product;
55 | _productType = zwaveNodeInfo.producttype;
56 | _productId = zwaveNodeInfo.productid;
57 | _type = zwaveNodeInfo.type;
58 | _name = zwaveNodeInfo.name;
59 | _location = zwaveNodeInfo.loc;
60 | _hash = _id + _manufacturerId + _productId;
61 | _ready = ready === true && _productType != '';
62 |
63 |
64 | _typeGeneric = decimalToHex(zwave.getNodeGeneric(_id),2);
65 | _typeSpecific = decimalToHex(zwave.getNodeSpecific(_id),2);
66 | _typeBasic = decimalToHex(zwave.getNodeBasic(_id), 2);
67 |
68 | }
69 |
70 | this.getNodeInformation = function () {
71 | return {
72 | id: _id,
73 | manufacturer: _manufacturer,
74 | manufacturerId: _manufacturerId,
75 | product: _product,
76 | productType: _productType,
77 | productId: _productId,
78 | type: _type,
79 | name: _name,
80 | location: _location,
81 | hash: _hash,
82 | ready: _ready,
83 | displayName: this.displayName,
84 | typeGeneric: _typeGeneric,
85 | typeSpecific: _typeSpecific,
86 | typeBasic: _typeBasic
87 | };
88 | }
89 |
90 | function decimalToHex(d, padding) {
91 | var hex = Number(d).toString(16);
92 | padding = typeof padding === typeof undefined || padding === null ? padding = 2 : padding;
93 |
94 | while (hex.length < padding) {
95 | hex = "0" + hex;
96 | }
97 |
98 | return ('0x' + hex).toUpperCase();
99 | }
100 |
101 | this.updateValue = function (zwaveValueInfo)
102 | {
103 | var zwaveClass = getZWaveClass(zwaveValueInfo);
104 | return zwaveClass.updateValue(zwaveValueInfo);
105 | }
106 |
107 | this.removeValue = function (commandClassId, instanceId, index) {
108 | for (var index = 0; index < _classes.length; index++) {
109 | if (_classes[index].id == commandClassId) {
110 | var zwaveClass = _classes[index];
111 | zwaveClass.removeValue(commandClassId, instanceId, index);
112 |
113 | if (zwaveClass.instances.length < 1) {
114 | _classes.splice(index, 1);
115 | }
116 |
117 | return;
118 | }
119 | }
120 | }
121 |
122 | this.getValue = function (commandClassId, instanceId, indexId) {
123 | var zwaveClass = null;
124 | for (var index = 0; index < _classes.length; index++) {
125 | if (_classes[index].id == commandClassId) {
126 | zwaveClass = _classes[index];
127 | break;
128 | }
129 | }
130 |
131 | if (zwaveClass != null)
132 | return zwaveClass.getValue(instanceId, indexId);
133 | else
134 | return null;
135 | }
136 |
137 | this.getClass = function (commandClassId) {
138 | for (var index = 0; index < _classes.length; index++) {
139 | if (_classes[index].id == commandClassId)
140 | return _classes[index];
141 | }
142 |
143 | return null;
144 | }
145 |
146 | function getZWaveClass(zwaveValueInfo) {
147 | for (var index = 0; index < _classes.length; index++) {
148 | if (_classes[index].id == zwaveValueInfo.class_id)
149 | return _classes[index];
150 | }
151 |
152 | var zwaveClass = new ZWaveClass(zwaveValueInfo.class_id)
153 | _classes.push(zwaveClass);
154 | return zwaveClass;
155 | }
156 |
157 |
158 | this.__defineGetter__('id', function () { return _id; });
159 | this.__defineGetter__('manufacturer', function () { return _manufacturer; });
160 | this.__defineGetter__('manufacturerId', function () { return _manufacturerId; });
161 | this.__defineGetter__('product', function () { return _product; });
162 | this.__defineGetter__('productType', function () { return _productType; });
163 | this.__defineGetter__('productId', function () { return _productId; });
164 | this.__defineGetter__('type', function () { return _type; });
165 | this.__defineGetter__('typeGeneric', function () { return _typeGeneric; });
166 | this.__defineGetter__('typeBasic', function () { return _typeBasic; });
167 | this.__defineGetter__('typeSpecific', function () { return _typeSpecific; });
168 | this.__defineGetter__('name', function () { return _name; });
169 | this.__defineSetter__('name', function (value) { _name = value; });
170 | this.__defineGetter__('location', function () { return _location; });
171 | this.__defineSetter__('location', function (value) { _location = value; });
172 | this.__defineGetter__('classes', function () { return _classes; });
173 | this.__defineGetter__('hash', function () { return _hash; });
174 | this.__defineGetter__('ready', function () { return _ready; });
175 | this.__defineGetter__('neighbors', function () { return _neighbors; });
176 | this.__defineGetter__('status', function () { return _status; });
177 | this.__defineSetter__('status', function (value) { _status = value; });
178 | this.__defineGetter__('displayName', function () {
179 | if (_name !== '')
180 | return _name;
181 | else if (_product !== '')
182 | return _product;
183 | else if (_type !== '')
184 | return _type;
185 | else
186 | return 'Unknown';
187 | });
188 | }
189 |
190 | module.exports = ZWaveNode
--------------------------------------------------------------------------------
/lib/zwave/zwaveValue.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // zwaveValue.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | var zwaveAlarmNotification = require('./zwaveAlarmNotification.js');
27 | var moment = require('moment');
28 |
29 | function ZWaveValue(zwaveValueInfo) {
30 | var _id = zwaveValueInfo.index;
31 | var _isReadOnly = zwaveValueInfo.read_only;
32 | var _isWriteOnly = zwaveValueInfo.write_only;
33 | var _type = zwaveValueInfo.type;
34 | var _label = zwaveValueInfo.label;
35 | var _help = zwaveValueInfo.help;
36 | var _units = zwaveValueInfo.units;
37 | var _valueId = zwaveValueInfo.value_id;
38 | var _genre = zwaveValueInfo.genre;
39 | var _isPolled = zwaveValueInfo.is_polled;
40 | var _values = zwaveValueInfo.values;
41 | var _min = zwaveValueInfo.min;
42 | var _max = zwaveValueInfo.max;
43 | var _firstUpdate = true;
44 | var _notificationType = null;
45 | var _status = 0;
46 | var _event = null;
47 | var _updateDateTimeUTC = null;
48 |
49 | convertNotificationValueToList();
50 |
51 | //convertNotificationValueToList before attempting the convert and setting default value.
52 | var _value = convertType(zwaveValueInfo.value);
53 |
54 | if ( typeof _value !== typeof undefined && _value.decoded === true) {
55 | _status = _value.status;
56 | _value = _value.value;
57 | }
58 |
59 | // set the notification status
60 | zwaveValueInfo.status = _status;
61 |
62 | this.__defineGetter__("id", function () { return _id; });
63 | this.__defineGetter__("isReadOnly", function () { return _isReadOnly; });
64 | this.__defineGetter__("isWriteOnly", function () { return _isWriteOnly; });
65 | this.__defineGetter__("type", function () { return _type; });
66 | this.__defineGetter__("label", function () { return _label; });
67 | this.__defineGetter__("help", function () { return _help; });
68 | this.__defineGetter__("units", function () { return _units; });
69 | this.__defineGetter__("value", function () { return _value; });
70 | this.__defineGetter__("min", function () { return _min; });
71 | this.__defineGetter__("max", function () { return _max; });
72 | this.__defineGetter__("genre", function () { return _genre; });
73 | this.__defineGetter__("isPolled", function () { return _isPolled; });
74 | this.__defineGetter__("values", function () { return _values; });
75 | this.__defineGetter__("valueId", function () { return _valueId; });
76 | this.__defineGetter__("status", function () { return _status; });
77 | this.__defineGetter__("updateDateTimeUTC", function () { return _updateDateTimeUTC; });
78 |
79 | function convertNotificationValueToList() {
80 | _notificationType = zwaveAlarmNotification.getNotificationType(zwaveValueInfo.class_id, zwaveValueInfo.index);
81 |
82 | // If this is a notification value then get the decoded list of known values
83 | // turn this value into a list instead of a number and fill the list with all the known values.
84 | // This may be handled by OpenZWave in the future
85 | if (typeof _notificationType !== typeof undefined) {
86 | _values = [];
87 | _type = 'list';
88 | for (_event in _notificationType.events) {
89 | _values.push(_notificationType.events[_event].value);
90 | }
91 |
92 | }
93 | }
94 |
95 | function convertType(value) {
96 | var result = value;
97 |
98 | if (typeof value === typeof undefined || value === null) {
99 | result = value;
100 | }
101 | else if (typeof value == 'string') {
102 | switch (_type) {
103 | case 'button':
104 | case 'string':
105 | case 'list':
106 | result = value;
107 | break;
108 | case 'int':
109 | case 'short':
110 | case 'byte':
111 | result = parseInt(value);
112 | break;
113 | case 'bool':
114 | result = value === 'true' || value === '1' || value === 1;
115 | break;
116 | case 'decimal':
117 | result = parseFloat(value);
118 | break;
119 | default:
120 | result = value;
121 | break;
122 |
123 | }
124 |
125 | }
126 | else if (_type === 'list' && typeof _notificationType !== typeof undefined && _notificationType !== null) {
127 | //
128 | // Change the current numeric values to more complex decoded objects values
129 | // which makes application logic easier up the stack
130 | //
131 |
132 | if (value === true) {
133 | result = _notificationType.events[1];
134 | } else if (value === false) {
135 | result = _notificationType.events[0];
136 | } else {
137 | result = _notificationType.events[value];
138 | }
139 |
140 | if (typeof result !== typeof undefined) {
141 | result.decoded = true;
142 | }
143 | else {
144 | result = value;
145 | }
146 |
147 | } else {
148 | result = value;
149 | }
150 |
151 | return result;
152 | }
153 |
154 | this.updateValue = function (zwaveValueInfo) {
155 | var result = false;
156 | var convertedValue = convertType(zwaveValueInfo.value);
157 | var status = 0;
158 |
159 | // if we have converted the value to decoded message
160 | if (typeof convertedValue !== typeof undefined && convertedValue.decoded === true) {
161 | // set the status to the status of the decoded message
162 | status = convertedValue.status;
163 | // use the new decoded message name as the value instead of the orginal numerical code
164 | convertedValue = convertedValue.value;
165 | }
166 |
167 | if (_value !== convertedValue || _firstUpdate === true) {
168 | result = true;
169 | zwaveValueInfo.new = true;
170 | }
171 | else if (_updateDateTimeUTC.getTime() + 60000 < (new Date(moment.utc().format())).getTime()) {
172 | result = true;
173 | zwaveValueInfo.new = false;
174 | } else {
175 | zwaveValueInfo.new = false;
176 | }
177 |
178 | // update our state
179 | _value = convertedValue;
180 | _status = status;
181 | _firstUpdate = false;
182 | _updateDateTimeUTC = new Date(moment.utc().format());
183 |
184 | zwaveValueInfo.value = _value;
185 | zwaveValueInfo.status = _status;
186 | zwaveValueInfo.units = _units;
187 |
188 | return result;
189 |
190 | };
191 |
192 | // This method is used to convert incomming values to the correct type before sending to OpenZWave
193 | // If the result is decoded, use the orginal numeric value for OpenZWave
194 | this.convert = function (value) {
195 | var result = convertType(value);
196 |
197 | if (result.decoded === true)
198 | result = result.id;
199 |
200 | return result;
201 | };
202 |
203 | }
204 |
205 | module.exports = ZWaveValue;
--------------------------------------------------------------------------------
/bin/bitdoghub:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | //-----------------------------------------------------------------------------
4 | //
5 | // bitdoghub
6 | //
7 | // Copyright (c) 2015-2017 Bitdog LLC.
8 | //
9 | // SOFTWARE NOTICE AND LICENSE
10 | //
11 | // This file is part of bitdog-hub.
12 | //
13 | // bitdog-hub is free software: you can redistribute it and/or modify
14 | // it under the terms of the GNU General Public License as published
15 | // by the Free Software Foundation, either version 3 of the License,
16 | // or (at your option) any later version.
17 | //
18 | // bitdog-hub is distributed in the hope that it will be useful,
19 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | // GNU General Public License for more details.
22 | //
23 | // You should have received a copy of the GNU General Public License
24 | // along with bitdog-hub. If not, see .
25 | //
26 | //-----------------------------------------------------------------------------
27 |
28 | var os = require('os');
29 | var path = require('path');
30 | var program = require('commander');
31 | var bitdogClient = require('bitdog-client');
32 | var child_process = require('child_process');
33 |
34 | function getPublicIPAddress() {
35 | var networkInterfaces = os.networkInterfaces( );
36 | var index = 0;
37 | var addresses = null;
38 | var interfaceName = '';
39 | var address = '127.0.0.1'
40 |
41 | for(interfaceName in networkInterfaces) {
42 | addresses = networkInterfaces[interfaceName]
43 | for(index = 0; index < addresses.length; index++)
44 | {
45 | address = addresses[index];
46 |
47 | if(address.family === 'IPv4' && address.address !== '127.0.0.1') {
48 | address = address.address ;
49 | break;
50 | }
51 | }
52 | }
53 |
54 | return address;
55 | }
56 |
57 | program
58 | .version('2.0.15');
59 |
60 | program.command('register')
61 | .description('Register this Bitdog Hub with Bitdog Cloud.')
62 | .option('-u,--username ', 'The username for the Bitdog IoT Cloud to register this hub with.')
63 | .option('-p,--passphrase ', 'The passphrase for the Bitdog IoT Cloud to register this hub with.')
64 | .option('-n,--nodename ', 'The name that will be displayed on the Bitdog IoT Cloud dashboard.')
65 | .action(function (options) {
66 |
67 | if (typeof options.passphrase === typeof undefined || typeof options.username === typeof undefined) {
68 | console.log('Please provide a username and passphrase when registering.');
69 | this.outputHelp();
70 | process.exit(0);
71 | }
72 | else {
73 | console.log('Registering node...')
74 | var adminManager = bitdogClient.adminManager;
75 |
76 | var nodeName = typeof options.nodename === typeof undefined ? 'New Node' : options.nodename;
77 | adminManager.registerNode(options.username, options.passphrase, nodeName,
78 | function (success) {
79 |
80 | console.log('Registration successful.');
81 | process.exit(0);
82 |
83 | },
84 | function (error) {
85 | console.log(error);
86 | process.exit(1);
87 | });
88 |
89 | }
90 |
91 |
92 | });
93 |
94 | program
95 | .command('start')
96 | .description('Start Bitdog Hub.')
97 | .option('-l,--logpath ', 'The path for log files.')
98 | .option('-c,--configpath ', 'The path for configuration files.')
99 | .option('-t,--tail', 'Write logs to console also.')
100 | .option('-e,--extension ', 'Path to file that has extension code. Use clear to remote extension from stored configuration.')
101 | .option('-d,--debug', 'Start remote debugging and wait for attachment.')
102 | .option('-p,--pidpath ', 'Specify a pid file path.')
103 |
104 |
105 | .action(function (options) {
106 | if(bitdogClient.configuration.isRegistered === false) {
107 | var readline = require('readline');
108 | var rl = readline.createInterface(process.stdin, process.stdout);
109 | rl.question("This Bitdog Hub is not registered, try automatic registration? (y/n) ", function(answer) {
110 | rl.close();
111 | if(answer === 'y')
112 | start(options);
113 | });
114 |
115 | } else {
116 | start(options);
117 | }
118 |
119 | function start(options) {
120 | var fs = require('fs');
121 | var packageFilePath = path.resolve(__dirname, '../');
122 | var debugScriptPath = path.resolve(__dirname, 'RemoteDebug.js');
123 | var pidFile = path.resolve(__dirname,'pid.txt');
124 | var args = [];
125 |
126 | var opt = {
127 | stdio: 'inherit',
128 | env: process.env,
129 | cwd: process.cwd(),
130 | detached: true
131 | };
132 |
133 | opt.env.LD_LIBRARY_PATH = '/usr/local/lib'
134 |
135 | if(options.pidpath) {
136 | console.log("Pid path option provided")
137 | pidFile = path.resolve(__dirname, options.pidpath);
138 | }
139 |
140 | console.log("Starting process with pid file at " + pidFile);
141 |
142 | if(options.debug) {
143 | console.log("Debug mode");
144 | args.push('--inspect-brk=' + getPublicIPAddress() + ':9229');
145 | args.push(packageFilePath);
146 | } else {
147 | args.push(packageFilePath);
148 | }
149 |
150 | if(options.tail) {
151 | args.push('--tail');
152 | console.log("Tailing log to console");
153 | }
154 |
155 | if(options.configpath) {
156 | args.push('--configpath');
157 | args.push(options.configpath);
158 |
159 | }
160 |
161 | if(options.logpath) {
162 | args.push('--logpath');
163 | args.push(options.logpath);
164 | }
165 |
166 | if(options.extension) {
167 | args.push('--extension');
168 | args.push(options.extension);
169 | }
170 |
171 | var child = child_process.spawn('node', args, opt);
172 | var pidId = child.pid;
173 |
174 | // required so the parent can exit
175 | child.unref();
176 |
177 | try {
178 | fs.writeFileSync(pidFile, pidId);
179 | }
180 | catch(error) {
181 | console.log("Could not write to pid file: " + error);
182 | }
183 |
184 | setTimeout(function() {
185 | try
186 | {
187 |
188 | child_process.execSync('/bin/kill -s 0 ' + pidId);
189 | console.log('Bitdog Hub started');
190 | process.exit(0);
191 |
192 | } catch(e) {
193 | console.log('Bitdog Hub has failed to start properly, pid:' + pidId);
194 | fs.unlinkSync(pidFile);
195 | process.exit(1);
196 | }
197 |
198 | }, 10000);
199 |
200 |
201 | }
202 |
203 | });
204 |
205 | program
206 | .command('stop')
207 | .description('Stop Bitdog Hub.')
208 | .option('-p,--pidpath ', 'Specify a pid file path.')
209 |
210 | .action(function (options) {
211 | var fs = require('fs');
212 | var packageFilePath = path.resolve(__dirname, '../');
213 | var pidFile = path.resolve(__dirname,'pid.txt');
214 |
215 | if(options.pidpath) {
216 | console.log("Pid path option provided")
217 | pidFile = path.resolve(__dirname, options.pidpath);
218 | }
219 |
220 | console.log("Stopping process with pid file at " + pidFile);
221 |
222 | try {
223 |
224 | try
225 | {
226 | fs.accessSync(pidFile, fs.F_OK);
227 | }
228 | catch(e) {
229 | console.log('Process id file not found, bitdog-hub may not be running');
230 | process.exit(1);
231 | }
232 |
233 | var pid = fs.readFileSync(pidFile);
234 | var pidId = parseInt(pid);
235 |
236 | try
237 | {
238 | process.kill(pidId,'SIGINT');
239 | }
240 | catch(e) {
241 | }
242 |
243 | setTimeout(function() {
244 | try
245 | {
246 | child_process.execSync('/bin/kill -s 0 ' + pidId);
247 | console.log('Bitdog Hub did not stop in timely fashion');
248 | process.exit(1);
249 |
250 | } catch(e) {
251 | console.log('Bitdog Hub has stopped');
252 | fs.unlinkSync(pidFile);
253 | process.exit(0);
254 | }
255 |
256 | }, 20000);
257 |
258 |
259 | } catch (e) {
260 | console.log(JSON.stringify(e));
261 | }
262 |
263 | });
264 |
265 | program
266 | .command('help')
267 | .description('Print usage and options.')
268 | .action(function(options) {
269 | program.outputHelp();
270 | });
271 |
272 |
273 | program.parse(process.argv);
274 |
275 | if (!process.argv.slice(2).length) {
276 | program.outputHelp();
277 | process.exit(1);
278 |
279 | }
280 |
281 |
282 |
283 |
--------------------------------------------------------------------------------
/lib/cameras/dvrManager.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // dvrManager.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | var bitdogClient = require('bitdog-client');
27 | var constants = require('../constants.js');
28 |
29 | var fs = require('fs');
30 | var request = require('request');
31 | var path = require('path');
32 | var dvrPath = bitdogClient.configuration.get(constants.VIDEO_DVR_PATH);
33 | var moment = require('moment');
34 |
35 | //
36 | // DVR manager watches the DVR directory for new motion capture jpegs and video mp4s. It uploads
37 | // then to the Bitdog cloud where they are saved in fault tolerant geo diversified storage. The files are made
38 | // availabe to the mobile app for security notifications and historical viewing.
39 | //
40 | function DVRManager() {
41 | var _isRunning = false;
42 | var _fileAssetUrl = '';
43 |
44 | this.__defineGetter__('isRunning', function () { return _isRunning; });
45 | this.__defineSetter__('isRunning', function (value) { _isRunning = value; });
46 |
47 | this.__defineGetter__('url', function () { return _fileAssetUrl; });
48 | this.__defineSetter__('url', function (value) { _fileAssetUrl = value; });
49 | }
50 |
51 | DVRManager.prototype.start = function (fileAssetUrl) {
52 | if (this.isRunning === true) {
53 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'Already in running state.');
54 | return;
55 | }
56 |
57 | this.url = fileAssetUrl;
58 |
59 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'Starting.');
60 |
61 | this.isRunning = true;
62 |
63 | // Start uploading in 60 seconds
64 | setTimeout(this.uploadFiles.bind(this), 60000);
65 |
66 | };
67 |
68 | DVRManager.prototype.stop = function () {
69 |
70 |
71 | if (this.isRunning === false) {
72 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'Already in stopped state.');
73 | return;
74 | }
75 |
76 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'Stopping.');
77 |
78 | this.isRunning = false;
79 |
80 |
81 |
82 | };
83 |
84 | DVRManager.prototype.uploadFiles = function (index) {
85 | var file = null;
86 | var fileExt = '';
87 | var promise = null;
88 | var self = this;
89 |
90 | if (this.isRunning === false)
91 | return;
92 |
93 | if (typeof index === typeof undefined)
94 | index = 0;
95 |
96 | var files = fs.readdirSync(dvrPath, { encoding: 'utf8' });
97 |
98 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'Found ' + files.length + ' for upload');
99 |
100 | if (files.length > 0) {
101 |
102 | // We caught up, reset the index
103 | if (index >= files.length)
104 | index = 0;
105 |
106 | fileName = files[index]
107 | fileExt = path.extname(fileName);
108 |
109 | if (fileExt !== '.jpg' && fileExt !== '.mp4') {
110 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'Ignoring file of incorrect type' + fileName);
111 | setTimeout(self.uploadFiles.bind(self), 1000, ++index);
112 | return;
113 | }
114 |
115 | var stat = fs.statSync(path.resolve(dvrPath, fileName));
116 | var now = moment();
117 | var lastAccess = moment(stat.mtime);
118 | var lastAccessInMinutes = now.diff(lastAccess, 'minutes',true);
119 |
120 | if ((lastAccessInMinutes < 2 && fileExt === '.mp4') || (lastAccessInMinutes < 1 && fileExt === '.jpg') ) {
121 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'File ' + fileName + ' was last accessed ' + lastAccessInMinutes + ' mintues ago. Ignoring file because its too new, maybe open');
122 | ++index;
123 |
124 | if (index === files.length)
125 | setTimeout(self.uploadFiles.bind(self), 60000, 0);
126 | else
127 | setTimeout(self.uploadFiles.bind(self), 1000, index);
128 |
129 | return;
130 |
131 | } else {
132 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'File ' + fileName + ' was last accessed ' + lastAccessInMinutes + ' minutes ago');
133 | }
134 |
135 | self.uploadFile(fileName,stat).then(function (result, error) {
136 |
137 | if (typeof error !== typeof undefined && error !== null) {
138 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER,'Error uploading file', error);
139 | // continue to next file if running
140 | }
141 |
142 | if (self.isRunning === true) {
143 | setTimeout(self.uploadFiles.bind(self), 1000, ++index);
144 | }
145 |
146 | }).catch(function (error) {
147 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, error);
148 | // continue to next file if running
149 |
150 | if (self.isRunning === true) {
151 | setTimeout(self.uploadFiles.bind(self), 1000, ++index);
152 | }
153 |
154 | });
155 |
156 |
157 | } else {
158 | if (self.isRunning === true) {
159 | // No files, wait 15 seconds and check again
160 | setTimeout(self.uploadFiles.bind(self), 15000, 0);
161 | }
162 | }
163 |
164 | };
165 |
166 | DVRManager.prototype.uploadFile = function (fileName, stat) {
167 | var self = this;
168 | var filePath = path.resolve(dvrPath, fileName);
169 |
170 | var promise = new Promise(function (resolve, reject) {
171 | try {
172 |
173 | var fileExt = path.extname(fileName);
174 | var contentType = '';
175 | var uri = '';
176 |
177 | switch (fileExt) {
178 | case '.jpg':
179 | contentType = 'image/jpeg';
180 | uri = '/uploadsecurityimage';
181 | break;
182 | case '.mp4':
183 | contentType = 'video/mp4';
184 | uri = '/uploadsecurityvideo';
185 | break;
186 | }
187 |
188 | var fileStream = fs.createReadStream(filePath, { flags: 'r' });
189 | var formData = {
190 | file: {
191 | value: fileStream ,
192 | options: { filename: fileName , contentType: contentType }
193 | },
194 | fileDateTimeUTC: moment(stat.ctime).toISOString()
195 | };
196 |
197 | request.post({ url: self.url + uri , formData: formData, headers: { node_id: bitdogClient.configuration.nodeId, auth_key: bitdogClient.configuration.authKey } }, function (error, httpResponse, body) {
198 |
199 | try {
200 | if (error !== null) {
201 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'File upload failed for ' + filePath, error);
202 | reject(error);
203 | } else {
204 |
205 | var result = null;
206 |
207 | try {
208 | result = JSON.parse(body);
209 | } catch (error){ }
210 |
211 | if (result !== null && result.Success === true ) {
212 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'Upload success, removing local file', filePath);
213 | fs.unlinkSync(filePath);
214 | resolve(result);
215 | } else {
216 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'File upload failed for ' + filePath, body);
217 | reject(error);
218 | }
219 | }
220 | }
221 | catch (error) {
222 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER, 'File upload failed for ' + filePath, error);
223 | reject(error);
224 | }
225 | });
226 |
227 | }
228 | catch (error) {
229 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_DVR_MANAGER,'File upload failed for ' + filePath, error);
230 | reject(error);
231 | }
232 |
233 | });
234 |
235 | return promise;
236 | };
237 |
238 | module.exports = new DVRManager();
--------------------------------------------------------------------------------
/lib/cameras/videoManager.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // videoManager.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 | 'use strict';
26 |
27 | let VideoStreamer = require('./videoStreamer.js');
28 | let dvrManager = require('./dvrManager.js');
29 |
30 | let url = require('url');
31 | let https = require('https');
32 | let http = require('http');
33 |
34 | let bitdogClient = require('bitdog-client');
35 | let constants = require('../constants.js');
36 | let childProcess = require('child_process');
37 |
38 | //
39 | // Video manager is an orchestator for multiple video sources amd streaming processes.
40 | // Each video source is given two separate processes that help stream video. One process is
41 | // ffmpeg encoder. The other process forwards the encoded video from ffmpeg to a cloud based
42 | // video hub via websockets. The video hub can broadcast the video to any securely connected viewing
43 | // applications. The cloud forwarder and video encoder are in external processes to prevent their message loops
44 | // from clogging up the hub's main message loop that handles automation and monitoring.
45 | //
46 |
47 | function VideoManager() {
48 | let _videoStreamers = [];
49 | let _isRunning = false;
50 |
51 | this.__defineGetter__('videoStreamers', function () { return _videoStreamers; });
52 |
53 | this.__defineGetter__('isRunning', function () { return _isRunning; });
54 | this.__defineSetter__('isRunning', function (value) { _isRunning = value; });
55 |
56 | }
57 |
58 | VideoManager.prototype.getVideoSources = function () {
59 | let capture = null;
60 | let devices = [];
61 |
62 | let result = childProcess.execFileSync('v4l2-ctl', ['--list-devices'], { encoding: 'utf8' });
63 | let records = result.split('\n\n');
64 | let record = null;
65 |
66 | for (let index = 0; index < records.length; index++) {
67 | record = records[index].trim();
68 |
69 | // Look for only loopback devices
70 | if (record.includes('loopback') === true) {
71 | capture = /(^.*):\s*(\W*\w*\W*\w*)/g.exec(record);
72 | if (capture !== null && capture.length > 2)
73 | devices.push({ description: capture[1], source: capture[2].replace('/dev/', ''), sourcePath: capture[2] });
74 | }
75 | }
76 |
77 | return devices;
78 | };
79 |
80 | VideoManager.prototype.start = function () {
81 | let self = this;
82 |
83 | if (this.isRunning === true)
84 | return;
85 |
86 | this.isRunning = true;
87 |
88 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Starting.');
89 |
90 | let videoSources = this.getVideoSources();
91 | let videoStreamer = null;
92 |
93 | if (videoSources.length > 0) {
94 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Found ' + videoSources.length + ' video sources.', videoSources);
95 |
96 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Acquiring video hub address.');
97 |
98 | bitdogClient.getVideoHubUrl(
99 | function (url) {
100 |
101 | for (let index = 0; index < videoSources.length; index++) {
102 | videoStreamer = new VideoStreamer(url, videoSources[index].source);
103 | self.videoStreamers.push(videoStreamer);
104 |
105 | videoStreamer.start();
106 | }
107 | },
108 | function (error) {
109 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Could not contact Bitdog Cloud for video.', error);
110 | },
111 | function (error) {
112 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Could not contact Bitdog Cloud for video.', error);
113 | }
114 | );
115 |
116 | bitdogClient.getFileAssetUrl(
117 | function (url) {
118 | dvrManager.start(url);
119 |
120 | },
121 | function (error) {
122 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Could not contact Bitdog Cloud for file asset management.', error);
123 | },
124 | function (error) {
125 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Could not contact Bitdog Cloud for file asset management.', error);
126 | }
127 | );
128 | } else {
129 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Did not find any video sources.');
130 | }
131 |
132 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Posting camera configuration.');
133 |
134 | saveCameraConfigurations(videoSources, function (result) {
135 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Posting camera configuration succeeded', result);
136 | }, function (error) {
137 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, error);
138 | });
139 |
140 | };
141 |
142 | VideoManager.prototype.stop = function () {
143 |
144 | if (this.isRunning === false)
145 | return;
146 |
147 | this.isRunning = false;
148 |
149 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_VIDEO_MANAGER, 'Stopping.');
150 |
151 | for (let index = 0; index < this.videoStreamers.length; index++) {
152 | this.videoStreamers[index].stop();
153 | }
154 |
155 | dvrManager.stop();
156 | };
157 |
158 | function saveCameraConfigurations(hubCameras, successCallback, errorCallback) {
159 | let self = this;
160 | let port = null;
161 | let protocol = null;
162 |
163 | let requestBody = {
164 | nodeId: bitdogClient.configuration.nodeId,
165 | authKey: bitdogClient.configuration.authKey,
166 | hubCamerasJson: JSON.stringify({ hubCameras: hubCameras })
167 | };
168 |
169 | let requestJson = JSON.stringify(requestBody);
170 |
171 | let headers = {
172 | 'Content-Type': 'application/json',
173 | };
174 |
175 | let parsedUrl = url.parse(bitdogClient.constants.CENTRAL_URL + '/realm/saveHubCameras');
176 |
177 | if (parsedUrl.port != null)
178 | port = parsedUrl.port;
179 | else {
180 | if (parsedUrl.protocol == 'http:')
181 | port = 80;
182 | else (parsedUrl.protocol == 'https:')
183 | port = 443;
184 | }
185 |
186 | let options = {
187 | host: parsedUrl.hostname,
188 | port: port,
189 | path: parsedUrl.pathname,
190 | method: 'POST',
191 | headers: headers
192 | };
193 |
194 | protocol = parsedUrl.protocol == 'https:' ? https : http;
195 |
196 | let request = protocol.request(options, function (response) {
197 | response.setEncoding('utf-8');
198 |
199 | let responseString = '';
200 |
201 | response.on('data', function (data) {
202 | responseString += data;
203 | });
204 |
205 | response.on('end', function () {
206 |
207 | if (this.statusCode == 200 && responseString.length > 1) {
208 | let resultObject = {};
209 |
210 | try {
211 | resultObject = JSON.parse(responseString);
212 | }
213 | catch (e) {
214 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_ZWAVE, 'Error parsing JSON from saveHubCameras:', e);
215 | errorCallback(responseString);
216 | }
217 |
218 | if (resultObject.Success === true) {
219 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_ZWAVE, 'Saved hub camera configurations');
220 |
221 | if (typeof successCallback !== typeof undefined) {
222 | successCallback(responseString);
223 | }
224 |
225 | return;
226 | }
227 |
228 | if (resultObject.Success !== true) {
229 | if (typeof errorCallback !== typeof undefined)
230 | errorCallback(responseString);
231 | return;
232 | }
233 |
234 | if (typeof errorCallback !== typeof undefined)
235 | errorCallback(responseString);
236 |
237 | }
238 | else {
239 | if (typeof errorCallback !== typeof undefined)
240 | errorCallback('Unexpected response from /realm/saveHubCameras. Status code: ' + this.statusCode + ' Response: ' + responseString);
241 | }
242 | });
243 | });
244 |
245 | request.on('error', function (e) {
246 | if (typeof errorCallback !== typeof undefined)
247 | errorCallback(e);
248 | });
249 |
250 | request.write(requestJson);
251 | request.end();
252 |
253 | }
254 |
255 | module.exports = new VideoManager();
--------------------------------------------------------------------------------
/lib/brains/bitdogBrain.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // bitdogBrain.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 | var EventEmitter = require('events').EventEmitter;
27 |
28 | var util = require('util');
29 | var path = require('path');
30 | var bitdogClient = require('bitdog-client');
31 | var constants = require('../constants.js');
32 | var coreMessageSchemas = require('../coreMessageSchemas.js');
33 | var tingodb = require('tingodb')();
34 | var databaseDirectoryPath = path.resolve(__dirname, '../../database');
35 |
36 |
37 | function BitdogBrain() {
38 | var _bitdogZWave = null;
39 |
40 | // Configure tingodb's folder setting
41 | this.db = new tingodb.Db(databaseDirectoryPath, {}, { memStore: false });
42 |
43 | // Create a file for zwave value persistence
44 | this.db.createCollection('zwaveValuesDb', {}, function (err, collection) {
45 | if (err != null) {
46 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error creating database collection zwaveValuesDb', err);
47 | } else {
48 | this.zwaveValuesDb = collection;
49 | }
50 |
51 | }.bind(this));
52 |
53 | // Create a file for zwave node configuration persistence
54 | this.db.createCollection('zwaveNodesDb', {}, function (err, collection) {
55 | if (err != null) {
56 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error creating database collection zwaveNodesDb', err);
57 | } else {
58 | this.zwaveNodesDb = collection;
59 | }
60 |
61 | }.bind(this));
62 |
63 | // Pass in the external zwave controller instance so that brain can send its own commands
64 | this.__defineGetter__('bitdogZWave', function () { return _bitdogZWave; });
65 | this.__defineSetter__('bitdogZWave', function (value) { _bitdogZWave = value; });
66 |
67 | }
68 |
69 | util.inherits(BitdogBrain, EventEmitter);
70 |
71 | BitdogBrain.prototype.processMessage = function (message) {
72 | this.onProcessMessage(message);
73 | }
74 |
75 | BitdogBrain.prototype.onProcessMessage = function (message) {
76 | //bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Processing message', message);
77 | // Process inbound and outbound messages
78 | switch (message.h.c) {
79 |
80 | case 'data':
81 | {
82 | switch (message.h.n) {
83 | case 'bd-zValueChanged':
84 | this.updateZWaveValue(message);
85 | break;
86 |
87 | case 'bd-zNodeRemoved':
88 | this.deleteZWaveNode(message);
89 | break;
90 |
91 | }
92 | }
93 | break;
94 |
95 | }
96 |
97 | }
98 |
99 | BitdogBrain.prototype.parseValueId = function (valueId) {
100 | var values = valueId.split('-');
101 | var result = {
102 | nodeId: parseInt(values[0]),
103 | classId: parseInt(values[1]),
104 | instanceId: parseInt(values[2]),
105 | indexId: parseInt(values[3])
106 | };
107 |
108 | return result;
109 | }
110 |
111 | BitdogBrain.prototype.updateZWaveValue = function (message) {
112 | var self = this;
113 | var key = message.d.homeId + '-' + message.d.valueId;
114 |
115 | self.zwaveValuesDb.findOne({ id: key }, {}, function (err, record) {
116 | if (err != null) {
117 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error finding data in zwaveValuesDb', err);
118 | }
119 | else {
120 |
121 | if (record != null && typeof record != typeof undefined) {
122 | self.zwaveValuesDb.update({ _id: record._id }, { id: key, value: message.d.value }, function (err, result) {
123 | if (err != null) {
124 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error updating data in zwaveValuesDb', err);
125 | }
126 |
127 | });
128 | }
129 | else {
130 | self.zwaveValuesDb.insert({ id: key, value: message.d.value }, {}, function (err, result) {
131 | if (err != null) {
132 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error inserting data into zwaveValuesDb', err);
133 | }
134 | });
135 | }
136 | }
137 |
138 | });
139 | }
140 |
141 | BitdogBrain.prototype.deleteZWaveNode = function (message) {
142 | var homeId = message.d.homeId;
143 | this.deleteNode(homeId, message.d.nodeInfo);
144 | }
145 |
146 | BitdogBrain.prototype.deleteNode = function (homeId, nodeInfo) {
147 | self = this;
148 |
149 | self.zwaveNodesDb.remove({ homeId: homeId, nodeId: nodeInfo.id }, {}, function (err, record) {
150 | if (err != null) {
151 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Problem with node:', node);
152 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error deleting data in zwaveNodesDb', err);
153 | }
154 | });
155 | }
156 |
157 |
158 | BitdogBrain.prototype.insertOrUpdateNode = function(homeId, node) {
159 | self = this;
160 |
161 | self.zwaveNodesDb.findOne({ homeId: homeId, nodeId: node.id }, {}, function (err, record) {
162 | if (err != null) {
163 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Problem with node:', node);
164 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error finding data in zwaveNodesDb', err);
165 | }
166 | else {
167 | if (record != null && typeof record != typeof undefined) {
168 | self.zwaveNodesDb.update({ homeId: homeId, nodeId: node.id }, { homeId: homeId, nodeId: node.id, node: node }, function (err, result) {
169 | if (err != null) {
170 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error updating data in zwaveNodesDb', err);
171 | }
172 |
173 | });
174 | }
175 | else {
176 |
177 | self.zwaveNodesDb.insert({ homeId: homeId, nodeId: node.id, node: node }, {}, function (err, result) {
178 | if (err != null) {
179 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Problem with node:', node);
180 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Error inserting data into zwaveNodesDb', err);
181 | }
182 | });
183 |
184 | self.emit('node added', node.getNodeInformation());
185 |
186 | bitdogClient.sendData('bd-zNodeFound', coreMessageSchemas.zwaveNodeMessageSchema, function (message) {
187 | message.homeId = homeId;
188 | message.nodeInfo = node.getNodeInformation();
189 | });
190 | }
191 | }
192 |
193 | });
194 | }
195 |
196 | BitdogBrain.prototype.getZWaveValue = function (homeId, nodeId, classId, instanceId, index) {
197 | var self = this;
198 | return new Promise(function (resolve, reject) {
199 | var id = homeId + '-' + nodeId + '-' + classId + instanceId + '-' + index;
200 | self.zwaveValuesDb.findOne({ id: id }, {}, function (err, record) {
201 | if (err == null) {
202 | resolve(record);
203 | } else {
204 | reject(err);
205 | }
206 |
207 | });
208 | });
209 |
210 | }
211 |
212 | BitdogBrain.prototype.getZWaveNode = function (homeId, nodeId) {
213 | var self = this;
214 | return new Promise(function (resolve, reject) {
215 | self.zwaveNodesDb.findOne({ homeId: homeId, nodeId: nodeId }, {}, function (err, record) {
216 | if (err == null) {
217 | resolve(record);
218 | } else {
219 | reject(err);
220 | }
221 |
222 | });
223 | });
224 |
225 | }
226 | //-------------------------------------------------------------------------------------
227 |
228 | BitdogBrain.prototype.setTemperature = function (homeId, nodeId, celsius) {
229 | var coolingSetpointValue = this.getZWaveValue(homeId, nodeId, 67, 1, 2);
230 | var heatingSetpointValue = this.getZWaveValue(homeId, nodeId, 67, 1, 1);
231 | var fahrenheit = ((c * 9) / 5) + 32;
232 |
233 | Promise.all([coolingSetpointValue, heatingSetpointValue]).then(function (values) {
234 | var coolingValue = values[0];
235 | var heatingValue = values[1];
236 |
237 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_BRAIN, 'Current themostat setpoint values', { homeId: homeId, nodeId: nodeId, cooling: coolingValue, heatingValue: heatingValue });
238 |
239 | // Currently setting both setpoints when this generic command is called
240 | if (coolingValue.unit === 'F' || heatingValue.unit === 'F') {
241 | bitdogZWave.setValue(nodeId, 67, 1, 2, fahrenheit);
242 | bitdogZWave.setValue(nodeId, 67, 1, 1, fahrenheit);
243 |
244 | } else {
245 | bitdogZWave.setValue(nodeId, 67, 1, 2, celsius);
246 | bitdogZWave.setValue(nodeId, 67, 1, 1, celsius);
247 | }
248 |
249 |
250 | });
251 | }
252 |
253 |
254 | module.exports = new BitdogBrain();
--------------------------------------------------------------------------------
/lib/alarm/bitdogAlarm.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // bitdogAlarm.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 |
28 | var EventProcessor = require('../eventProcessor.js').EventProcessor;
29 | var Zone = require('./zone.js');
30 | var util = require('util');
31 | var bitdogClient = require('bitdog-client');
32 | var alarmMode = require('./alarmMode.js');
33 | var coreMessageSchemas = require('../coreMessageSchemas.js');
34 | var constants = require('../constants.js');
35 |
36 |
37 | function BitdogAlarm() {
38 | var _zones = [];
39 | var _bitdogZWave = null;
40 | var _alarmMode = alarmMode.disarmed;
41 | var _monitoredDevices = {};
42 | var _isAlarmed = false;
43 |
44 | this.__defineGetter__('zones', function () { return _zones; });
45 | this.__defineSetter__('zones', function (value) { _zones = value; });
46 |
47 | this.__defineGetter__('alarmMode', function () { return _alarmMode; });
48 |
49 | this.__defineSetter__('alarmMode', function (value) {
50 | if (typeof value !== typeof undefined && value !== null && _alarmMode !== value) {
51 | _alarmMode = value;
52 |
53 | bitdogClient.sendData('bd-alarmStatus', coreMessageSchemas.alarmStatusMessageSchema, function (message) {
54 | message.alarmMode = value;
55 | });
56 |
57 | }
58 | });
59 |
60 |
61 | this.__defineGetter__('monitoredDevices', function () { return _monitoredDevices; });
62 | this.__defineSetter__('monitoredDevices', function (value) { _monitoredDevices = value; });
63 |
64 | this.__defineGetter__('isAlarmed', function () { return _isAlarmed; });
65 | this.__defineSetter__('isAlarmed', function (value) { _isAlarmed = value; });
66 |
67 | // Pass in the external zwave controller instance
68 | this.__defineGetter__('bitdogZWave', function () { return _bitdogZWave; });
69 | this.__defineSetter__('bitdogZWave', function (value) { _bitdogZWave = value; });
70 |
71 | }
72 |
73 | util.inherits(BitdogAlarm, EventProcessor);
74 |
75 | BitdogAlarm.prototype.onProcessMessage = function (message) {
76 | var key = null;
77 | var zones = null;
78 | var nodeDisplayName = null;
79 |
80 | // We need to do full processing of the event
81 | // Even if the system is not armed for burglar because a safety event may occur
82 | if (message.c.n === bitdogClient.configuration.nodeId && typeof message.h !== typeof undefined && message.h !== null && message.h.n === 'bd-zValueChanged') {
83 | if (typeof message.d !== typeof undefined && message.d !== null && typeof message.d.homeId !== typeof undefined && message.d.homeId !== null) {
84 | // key is hub id / home id / zwave device id
85 | key = message.c.n + '/' + message.d.homeId + '/' + message.d.nodeId;
86 |
87 | // See if this device is associated to any zones by its unique key
88 | zones = this.monitoredDevices[key];
89 |
90 | // Get the zwave devices display name
91 | nodeDisplayName = this.bitdogZWave.getNodeDisplayName(message.d.nodeId);
92 |
93 | // 'message.d.status & 1 === 1' is a bit check for the burglar bit in status - reference zwaveAlarmNotification.js
94 | // 'message.d.status & 16 === 16' is a bit check for the burglar event bit in status
95 | // burglar bit indicates a value that is stateful, like window open
96 | // burglarEvent bit indicates a transient event like keypad key pressed
97 | // statefulness matters because in the user interface we want to show a state of the device
98 | // a locked lock shows its state as ok from a security stand point, but a key pad press can set off alarm even though the door is still locked
99 | if (typeof zones !== typeof undefined) {
100 |
101 | // burglarAlarm or burglarEventAlarm
102 | if (((message.d.status & 1) === 1) || ((message.d.status & 16) === 16)) {
103 | if (this.alarmMode != alarmMode.disarmed) {
104 | this.isAlarmed = true;
105 |
106 |
107 | bitdogClient.sendData('bd-alarmEvent', coreMessageSchemas.alarmEventMessageSchema, function (newMessage) {
108 | newMessage.status = alarmMode.securityAlarm;
109 | newMessage.event = message;
110 | newMessage.zones = zones.map(function (zone) {
111 | return { name: zone.name, id: zone.id };
112 | });
113 | newMessage.device = nodeDisplayName;
114 |
115 | if (typeof message.d.value !== typeof undefined && message.d.value !== null)
116 | newMessage.value = message.d.value.toString();
117 | });
118 | }
119 | }
120 |
121 | // safety alarm should fire even when the system is not armed
122 | if ((message.d.status & 8) === 8) {
123 | this.isAlarmed = true;
124 |
125 | bitdogClient.sendData('bd-alarmEvent', coreMessageSchemas.alarmEventMessageSchema, function (newMessage) {
126 | newMessage.status = alarmMode.safetyAlarm;
127 | newMessage.event = message;
128 | newMessage.zones = zones.map(function (zone) {
129 | return { name: zone.name, id: zone.id };
130 | });
131 | newMessage.device = nodeDisplayName;
132 |
133 | if (typeof message.d.value !== typeof undefined && message.d.value !== null)
134 | newMessage.value = message.d.value.toString();
135 |
136 | });
137 | }
138 | }
139 | }
140 | } else {
141 |
142 | if (message.c.n === bitdogClient.configuration.nodeId && typeof message.h !== typeof undefined && message.h !== null && (message.h.n === 'bd-videoMotionEventStart')) {
143 |
144 | // source path not supported yet, only one camera at the moment.
145 | key = message.c.n + '//dev/video1'; // + '//' + message.d.sourcePath;
146 |
147 | // See if this device is associated to any zones by its unique key
148 | zones = this.monitoredDevices[key];
149 |
150 | if (typeof zones !== typeof undefined) {
151 |
152 | if (this.alarmMode != alarmMode.disarmed) {
153 | this.isAlarmed = true;
154 |
155 | bitdogClient.sendData('bd-alarmEvent', coreMessageSchemas.alarmEventMessageSchema, function (newMessage) {
156 | newMessage.status = alarmMode.securityAlarm;
157 | newMessage.event = message;
158 | newMessage.zones = zones.map(function (zone) {
159 | return { name: zone.name, id: zone.id };
160 | });
161 | newMessage.value = 'Video Motion Detected';
162 | });
163 | }
164 |
165 | }
166 |
167 | }
168 |
169 | }
170 | }
171 |
172 |
173 |
174 | BitdogAlarm.prototype.armAway = function (message) {
175 |
176 | if (this.alarmMode !== alarmMode.away) {
177 | this.alarmMode = alarmMode.away; // set mode before loading zones, it matters
178 | this.loadZones();
179 |
180 | bitdogClient.configuration.set(constants.ALARM_NODE, this.alarmMode);
181 |
182 | }
183 |
184 | bitdogClient.sendData('bd-alarmEvent', coreMessageSchemas.alarmEventMessageSchema, function (newMessage) {
185 | newMessage.status = alarmMode.alarmClear;
186 | newMessage.event = message;
187 | });
188 |
189 | this.isAlarmed = false;
190 | };
191 |
192 | BitdogAlarm.prototype.armStay = function (message) {
193 |
194 | if (this.alarmMode !== alarmMode.stay) {
195 | this.alarmMode = alarmMode.stay; // set mode before loading zones, it matters
196 | this.loadZones();
197 | bitdogClient.configuration.set(constants.ALARM_NODE, this.alarmMode);
198 |
199 | }
200 |
201 | bitdogClient.sendData('bd-alarmEvent', coreMessageSchemas.alarmEventMessageSchema, function (newMessage) {
202 | newMessage.status = alarmMode.alarmClear;
203 | newMessage.event = message;
204 | });
205 |
206 | this.isAlarmed = false;
207 |
208 | };
209 |
210 | BitdogAlarm.prototype.disarm = function (message) {
211 |
212 | if (this.alarmMode !== alarmMode.disarmed) {
213 | this.alarmMode = alarmMode.disarmed;
214 | bitdogClient.configuration.set(constants.ALARM_NODE, this.alarmMode);
215 | }
216 |
217 | bitdogClient.sendData('bd-alarmEvent', coreMessageSchemas.alarmEventMessageSchema, function (newMessage) {
218 | newMessage.status = alarmMode.alarmClear;
219 | newMessage.event = message;
220 | });
221 |
222 | this.isAlarmed = false;
223 |
224 | };
225 |
226 | BitdogAlarm.prototype.loadZones = function () {
227 | var zoneIndex = 0;
228 | var deviceIndex = 0;
229 | var zone = null;
230 | var definition = null;
231 | var nodeId = null;
232 | var zwaveNodeId = null;
233 | var zoneDevices = null;
234 | var zoneDevice = null;
235 | var shouldAddDevice = false;
236 | var zones = null;
237 |
238 | this.zones = bitdogClient.configuration.get(constants.ZONES_CONFIG);
239 | this.monitoredDevices = {};
240 |
241 | if (typeof this.zones !== typeof undefined && this.zones !== null) {
242 | for (zoneIndex = 0; zoneIndex < this.zones.length; zoneIndex++) {
243 | zone = this.zones[zoneIndex];
244 | definition = zone.definition;
245 | if (typeof definition !== typeof undefined && definition !== null) {
246 | zoneDevices = definition.zoneDevices;
247 | if (typeof zoneDevices !== typeof undefined && zoneDevices !== null) {
248 | for (deviceIndex in zoneDevices) {
249 | shouldAddDevice = false;
250 | zoneDevice = zoneDevices[deviceIndex];
251 |
252 | if (zoneDevice.include === true) {
253 | // some devices are not for away and stay but for safety
254 | if (typeof zoneDevice.away === typeof undefined && typeof zoneDevice.stay === typeof undefined) {
255 | shouldAddDevice = true;
256 | } else if (zoneDevice.stay === true && this.alarmMode === alarmMode.stay) {
257 | shouldAddDevice = true;
258 | } else if (zoneDevice.away === true && this.alarmMode === alarmMode.away) {
259 | shouldAddDevice = true;
260 | }
261 | }
262 |
263 | if (shouldAddDevice === true) {
264 | zones = this.monitoredDevices[deviceIndex];
265 |
266 | if (typeof zones === typeof undefined || zones === null) {
267 | zones = [];
268 | this.monitoredDevices[deviceIndex] = zones;
269 | }
270 |
271 | zones.push(zone);
272 | }
273 |
274 | }
275 | }
276 | }
277 |
278 | }
279 | }
280 | };
281 |
282 | module.exports = new BitdogAlarm();
--------------------------------------------------------------------------------
/lib/automation/scheduler.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // scheduler.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 | 'use strict';
26 | let SunCalc = require('suncalc');
27 | let bitdogClient = require('bitdog-client');
28 | let constants = require('../constants.js');
29 | let coreMessageSchemas = require('../coreMessageSchemas.js');
30 | let moment = require('moment');
31 | let weatherManager = require('./weatherManager.js');
32 |
33 | function Scheduler(automationConfiguration) {
34 |
35 | let _schedules = {};
36 | let _weatherForecast = null;
37 | let _automationConfiguration = automationConfiguration;
38 |
39 | this.__defineGetter__('automationConfiguration', function () { return _automationConfiguration; });
40 |
41 | this.__defineGetter__('schedules', function () { return _schedules; });
42 | this.__defineSetter__('schedules', function (value) { _schedules = value; });
43 |
44 | this.__defineGetter__('weatherForecast', function () { return _weatherForecast; });
45 | this.__defineSetter__('weatherForecast', function (value) { _weatherForecast = value; });
46 |
47 | }
48 |
49 | Scheduler.prototype.createTodaysSchedule = function () {
50 | let now = new Date();
51 | this.schedules = {};
52 | this.schedules.dayOfWeek = this.getDayOfWeek();
53 |
54 | let automation = null;
55 | let name = null;
56 | let automationId = null;
57 | let definition = null;
58 | let trigger = null;
59 | let targetTime = null;
60 | let index = null;
61 | let hour = null;
62 | let minute = null;
63 | let location = null;
64 | let astronomicalTimes = null;
65 |
66 | try {
67 |
68 | for (index = 0; index < this.automationConfiguration.length; index++) {
69 | automation = this.automationConfiguration[index];
70 | name = automation.Name;
71 | automationId = automation.AutomationId;
72 | definition = automation.Definition;
73 | trigger = definition.trigger;
74 | targetTime = null;
75 |
76 | switch (trigger.triggerId) {
77 | case 'recurringTime':
78 |
79 | switch (trigger.dateTimeId) {
80 | case 'weekdays':
81 | if (trigger.weekdays[this.schedules.dayOfWeek] !== true)
82 | break;
83 |
84 | case 'everyDay':
85 |
86 | if (trigger.timeTypeId === 'specific') {
87 | hour = parseInt(trigger.hour);
88 | minute = parseInt(trigger.minute);
89 |
90 | if (trigger.amPm.toLowerCase() === 'pm')
91 | hour += 12;
92 |
93 | targetTime = moment();
94 | targetTime.hour(hour);
95 | targetTime.minute(minute);
96 | targetTime.second(0);
97 |
98 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Target time ' + trigger.timeTypeId + ' for automation \'' + name + '\': ' + targetTime.format());
99 |
100 | if (targetTime.isSameOrAfter(now)) {
101 | this.addAutomationToSchedule(targetTime, automation);
102 | }
103 | }
104 | else {
105 | location = bitdogClient.configuration.get(constants.AUTOMATIONS_LOCATION);
106 |
107 | if (typeof location !== typeof undefined && location !== null) {
108 | astronomicalTimes = this.getAstronomicalTimes(location.latitude, location.longitude);
109 | targetTime = moment(astronomicalTimes[trigger.timeTypeId]);
110 |
111 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Target time ' + trigger.timeTypeId + ' for automation \'' + name + '\': ' + targetTime.format());
112 |
113 | if (typeof trigger.offsetTypeId !== typeof undefined && typeof trigger.offsetMinutes !== typeof undefined) {
114 | switch (trigger.offsetTypeId) {
115 | case 'before':
116 | targetTime.subtract(trigger.offsetMinutes, 'minutes');
117 | break;
118 | case 'after':
119 | targetTime.add(trigger.offsetMinutes, 'minutes');
120 | break;
121 | }
122 |
123 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Target has offset for ' + trigger.offsetMinutes + ' minutes ' + trigger.offsetTypeId + ' ' + trigger.timeTypeId + ', new target time for automation \'' + name + '\': ' + targetTime.format());
124 |
125 | }
126 |
127 | if (targetTime.isSameOrAfter(now)) {
128 | this.addAutomationToSchedule(targetTime, automation);
129 | }
130 | } else {
131 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Location not set and cannot calculate ' + trigger.timeTypeId + ' for automation \'' + name + '\': ' + targetTime.format());
132 |
133 | }
134 | }
135 | break;
136 | case 'everyHour':
137 | break;
138 |
139 | }
140 |
141 | break;
142 | case 'deviceValueChanges':
143 | break;
144 | case 'valueChangesAnyDevice':
145 | break;
146 |
147 | }
148 |
149 | }
150 |
151 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Calculated todays schedule', this.schedules);
152 |
153 | bitdogClient.sendData('bd-automationScheduled', coreMessageSchemas.automationScheduledMessageSchema, function (message) {
154 | let items = [];
155 | let time = null;
156 | let index = 0;
157 | let item = null;
158 |
159 | for (time in this.schedules) {
160 | if (time !== 'dayOfWeek') {
161 | for (index = 0; index < this.schedules[time].length; index++) {
162 | item = this.schedules[time][index];
163 | items.push({
164 | automationId: item.AutomationId, executionTime: item.scheduledExecutionDateTime
165 | });
166 | }
167 | }
168 | }
169 |
170 | message.schedule = items;
171 | }.bind(this));
172 | }
173 | catch (e) {
174 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Could not calculate schedule', e);
175 |
176 | }
177 | }
178 |
179 | Scheduler.prototype.addAutomationToSchedule = function (momentValue, automation) {
180 | let timeValue = momentValue.unix().toString();
181 | automation.scheduledExecutionDateTime = momentValue.utc().format();
182 |
183 | if (typeof this.schedules[timeValue] === typeof undefined)
184 | this.schedules[timeValue] = [];
185 |
186 | this.schedules[timeValue].push(automation);
187 | }
188 |
189 | Scheduler.prototype.tock = function () {
190 |
191 | if (this.schedules.dayOfWeek !== this.getDayOfWeek()) {
192 | this.createTodaysSchedule();
193 | }
194 | else {
195 | let now = moment();
196 | let fiveMinutesAgo = moment(); fiveMinutesAgo.subtract(5, 'minutes');
197 | let schedules = [];
198 | let automation = null;
199 | let definition = null;
200 | let name = null;
201 | let executedTimes = [];
202 | let timeValue = null;
203 | let messageResult = null;
204 | let automationIndex = 0;
205 | let commandIndex = 0;
206 |
207 | for (timeValue in this.schedules) {
208 |
209 | if (timeValue === 'dayOfWeek') // ignore variable property on schedules
210 | continue;
211 |
212 | let time = moment.unix(parseInt(timeValue));
213 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Comparing times', { time: time.format() });
214 |
215 | // Between now and five minutes ago
216 | if (time.isSameOrAfter(fiveMinutesAgo) && time.isSameOrBefore(now)) {
217 | schedules = this.schedules[timeValue];
218 | executedTimes.push(timeValue);
219 |
220 |
221 | for (automationIndex = 0; automationIndex < schedules.length; automationIndex++) {
222 | automation = schedules[automationIndex];
223 | definition = automation.Definition;
224 | name = automation.Name;
225 |
226 | bitdogClient.sendData('bd-automationExecuted', coreMessageSchemas.automationExecutedMessageSchema, function (message) {
227 | message.automationId = automation.AutomationId;
228 | });
229 |
230 | for (commandIndex = 0; commandIndex < definition.commands.length; commandIndex++) {
231 | messageResult = bitdogClient.sendMessage(definition.commands[commandIndex].message);
232 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Executed automation: \'' + name + '\' command: \'' + definition.commands[commandIndex].name + '\'', messageResult);
233 | }
234 | }
235 |
236 | }
237 |
238 |
239 | }
240 |
241 | for (let timesIndex = 0; timesIndex < executedTimes.length; timesIndex++) {
242 | timeValue = executedTimes[timesIndex];
243 | delete this.schedules[timeValue];
244 | }
245 |
246 |
247 | }
248 | };
249 |
250 | Scheduler.prototype.weatherTock = function () {
251 | let location = bitdogClient.configuration.get(constants.AUTOMATIONS_LOCATION);
252 | let self = this;
253 |
254 | if (typeof location !== typeof undefined && location !== null) {
255 | bitdogClient.sendCommand(constants.BITDOG_CLOUD_NODE, 'bd-getWeatherCurrent', coreMessageSchemas.weatherRequestMessageSchema, function (message) {
256 | message.lat = location.latitude;
257 | message.long = location.longitude;
258 | }).then(function (commandResult) {
259 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Retrieved weather forecast');
260 | self.weatherForecast = commandResult.result.value;
261 | weatherManager.processWeatherForecast(self.weatherForecast);
262 | }, function (error) {
263 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Could not retrieve weather forecast', error);
264 | });
265 | }
266 | };
267 |
268 | Scheduler.prototype.getDayOfWeek = function () {
269 | return moment().format('dddd').toLowerCase();
270 | };
271 |
272 | Scheduler.prototype.getAstronomicalTimes = function (latitude, longitude) {
273 | let todayAtNoon = new Date();
274 | todayAtNoon.setHours(12);
275 |
276 | // Using noon to avoid the wrong day being picked when too close to midnight
277 | return SunCalc.getTimes(todayAtNoon, latitude, longitude);
278 | }
279 |
280 | module.exports = Scheduler;
--------------------------------------------------------------------------------
/lib/automation/eventCapturer.js:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | //
3 | // eventCapturer.js
4 | //
5 | // Copyright (c) 2015-2017 Bitdog LLC.
6 | //
7 | // SOFTWARE NOTICE AND LICENSE
8 | //
9 | // This file is part of bitdog-hub.
10 | //
11 | // bitdog-hub is free software: you can redistribute it and/or modify
12 | // it under the terms of the GNU General Public License as published
13 | // by the Free Software Foundation, either version 3 of the License,
14 | // or (at your option) any later version.
15 | //
16 | // bitdog-hub is distributed in the hope that it will be useful,
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | // GNU General Public License for more details.
20 | //
21 | // You should have received a copy of the GNU General Public License
22 | // along with bitdog-hub. If not, see .
23 | //
24 | //-----------------------------------------------------------------------------
25 |
26 |
27 | var SunCalc = require('suncalc');
28 | var bitdogClient = require('bitdog-client');
29 | var constants = require('../constants.js');
30 | var coreMessageSchemas = require('../coreMessageSchemas.js');
31 | var moment = require('moment');
32 |
33 |
34 | function EventCapturer(automationConfiguration) {
35 | var _automationConfiguration = automationConfiguration;
36 | var _captureList = {};
37 |
38 |
39 | this.__defineGetter__('automationConfiguration', function () { return _automationConfiguration; });
40 | this.__defineGetter__('captureList', function () { return _captureList; });
41 |
42 |
43 | this.createEventCaptureList();
44 |
45 | }
46 |
47 | EventCapturer.prototype.createEventCaptureList = function () {
48 | for (var index = 0; index < this.automationConfiguration.length; index++) {
49 | var automation = this.automationConfiguration[index];
50 | var name = automation.Name;
51 | var automationId = automation.AutomationId;
52 | var definition = automation.Definition;
53 | var trigger = definition.trigger;
54 |
55 | switch (trigger.triggerId) {
56 | case 'recurringTime':
57 | break;
58 | case 'deviceValueChanges':
59 | this.addAutomationToEventCapturer(trigger.reference.id, automation);
60 | break;
61 | case 'valueChangesAnyDevice':
62 | this.addAutomationToEventCapturer(trigger.classId + '/' + trigger.propertyId, automation);
63 | break;
64 | case 'sceneEvent':
65 | this.addAutomationToEventCapturer(trigger.reference.id + '/' + trigger.value, automation);
66 | break;
67 |
68 | }
69 | }
70 |
71 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Created event capture list', this.captureList);
72 |
73 | };
74 |
75 | EventCapturer.prototype.addAutomationToEventCapturer = function (eventId, automation) {
76 | if (typeof this.captureList[eventId] === typeof undefined)
77 | this.captureList[eventId] = [];
78 |
79 | this.captureList[eventId].push(automation);
80 | };
81 |
82 | EventCapturer.prototype.onProcessMessage = function (message) {
83 | var id = this.calculateId(message);
84 | var definition = null;
85 | var name = null;
86 | var logic = null;
87 | var trigger = null;
88 | var propertyName = null;
89 | var automations = [];
90 | var specific = this.captureList[id.specific];
91 | var generic = this.captureList[id.generic];
92 |
93 | if (typeof specific !== typeof undefined && specific != null) {
94 | automations = automations.concat(specific);
95 | }
96 |
97 | if (typeof generic !== typeof undefined && generic != null) {
98 | automations = automations.concat(generic);
99 | }
100 |
101 | for (var automationIndex = 0; automationIndex < automations.length; automationIndex++) {
102 | automation = automations[automationIndex];
103 | definition = automation.Definition;
104 | trigger = definition.trigger;
105 | name = automation.Name;
106 |
107 | if (this.compare(message, trigger) === true) {
108 |
109 | if (this.shouldIgnore(definition) === false) { // This step potentially requires heavier computation, so its checked second
110 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Trigger matched message for automation: \'' + name + '\'', message);
111 |
112 | bitdogClient.sendData('bd-automationExecuted', coreMessageSchemas.automationExecutedMessageSchema, function (message) {
113 | message.automationId = automation.AutomationId;
114 | });
115 |
116 | for (var commandIndex = 0; commandIndex < definition.commands.length; commandIndex++) {
117 | messageResult = bitdogClient.sendMessage(definition.commands[commandIndex].message);
118 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Executed automation: \'' + name + '\'', messageResult);
119 | }
120 | }
121 | else {
122 |
123 | bitdogClient.logger.logProcessEvent(constants.LOG_PROCESS_AUTOMATION, 'Trigger matched message for automation, but it has been filtered: \'' + name + '\'', message);
124 |
125 | }
126 | }
127 | }
128 |
129 |
130 |
131 | };
132 |
133 | EventCapturer.prototype.shouldIgnore = function (definition) {
134 | var triggerFilter = definition.triggerFilter;
135 | var now = new Date();
136 | var result = true;
137 | var location = bitdogClient.configuration.get(constants.AUTOMATIONS_LOCATION);
138 |
139 |
140 | if (triggerFilter.filterTypeId === 'always') {
141 | result = false;
142 | } else if (triggerFilter.filterTypeId === 'betweenTimes') {
143 | var startTime = this.getTargetTime(triggerFilter.start, location.latitude, location.longitude);
144 | var endTime = this.getTargetTime(triggerFilter.end, location.latitude, location.longitude);
145 |
146 | if (startTime.isSame(endTime)) { // invalid value, ignore
147 | result = true;
148 | } else if (endTime.isBefore(startTime)) { // schedule crosses days
149 |
150 | if (endTime.isAfter(now)) { // start was yesterday and we haven't ended yet
151 | result = false; // don't ignore
152 | }
153 | else if (startTime.isSameOrBefore(now)) { // we started and the end is tomorrow
154 | result = false; // don't ignore
155 | } else {
156 | result = true; // ignore
157 | }
158 |
159 | } else if (startTime.isSameOrBefore(now) && endTime.isAfter(now)) { // now is between start and end, don't ignore
160 | result = false;
161 | }
162 | }
163 |
164 | return result;
165 |
166 | }
167 |
168 | EventCapturer.prototype.getTargetTime = function (timeDefintion, latitude, longitude) {
169 |
170 | var targetTime = null;
171 | var now = new Date();
172 |
173 |
174 | if (timeDefintion.timeTypeId === 'specific') {
175 | var hour = parseInt(timeDefintion.hour);
176 | var minute = parseInt(timeDefintion.minute);
177 |
178 | if (timeDefintion.amPm.toLowerCase() === 'pm')
179 | hour += 12;
180 |
181 | targetTime = moment();
182 | targetTime.hour(hour);
183 | targetTime.minute(minute);
184 | targetTime.second(0);
185 |
186 | }
187 | else {
188 |
189 | var astronomicalTimes = this.getAstronomicalTimes(latitude, longitude);
190 | targetTime = moment(astronomicalTimes[timeDefintion.timeTypeId]);
191 | }
192 |
193 | return targetTime;
194 |
195 | }
196 |
197 | // This is used to determine the unique id of what is changing
198 | EventCapturer.prototype.calculateId = function (message) {
199 | var id = { specific: null, generic: null };
200 |
201 |
202 | switch (message.h.n) {
203 | case 'bd-zValueChanged':
204 | id.specific = message.c.n + '/' + message.d.homeId + '/' + message.d.nodeId + '/' + message.d.classId + '/' + message.d.instanceId + '/' + message.d.indexId;
205 | id.generic = message.d.classId + '/' + message.d.indexId
206 | break;
207 |
208 | case 'bd-zSceneEvent':
209 | id.specific = message.c.n + '/' + message.d.homeId + '/' + message.d.nodeId + '/' + message.d.value;
210 | break;
211 |
212 | default:
213 | id.specific = message.c.n + '/' + message.h.n;
214 | // the following is not supported yet
215 | id.generic = message.h.n;
216 | break;
217 | }
218 |
219 | return id;
220 |
221 | }
222 |
223 | EventCapturer.prototype.getAstronomicalTimes = function (latitude, longitude) {
224 | var todayAtNoon = new Date();
225 | todayAtNoon.setHours(12);
226 |
227 | // Using noon to avoid the wrong day being picked when too close to midnight
228 | return SunCalc.getTimes(todayAtNoon, latitude, longitude);
229 | }
230 |
231 | EventCapturer.prototype.compare = function (message, trigger) {
232 | var results = true;
233 | var logic = trigger.logic;
234 |
235 | if (typeof trigger.classId != typeof undefined || typeof trigger.reference.zwaveNodeId !== typeof undefined) {
236 | for (var property in logic) {
237 | switch (logic[property]) {
238 | case 'ignore':
239 | break;
240 | case '=':
241 | results = results && (message.d.value == trigger.value);
242 | break;
243 | case '!=':
244 | results = results && (message.d.value != trigger.value);
245 | break;
246 | case '>':
247 | results = results && (message.d.value > trigger.value);
248 | break;
249 | case '>=':
250 | results = results && (message.d.value >= trigger.value);
251 | break;
252 | case '<':
253 | results = results && (message.d.value < trigger.value);
254 | break;
255 | case '<=':
256 | results = results && (message.d.value <= trigger.value);
257 | break;
258 | case 'between':
259 | results = results && (message.d.value > trigger.value && message.d.value < trigger.value2);
260 | break;
261 | case 'starts with':
262 | results = results && typeof message.d.value != typeof undefined && message.d.value != null && message.d.value.startsWith(trigger.value);
263 | break;
264 | case 'ends with':
265 | results = results && typeof message.d.value != typeof undefined && message.d.value != null && message.d.value.endsWith(trigger.value);
266 | break;
267 | case 'contains':
268 | results = results && typeof message.d.value != typeof undefined && message.d.value != null && message.d.value.indexOf(trigger.value) != -1;
269 | break;
270 | case "equals":
271 | results = results && (message.d.value == trigger.value);
272 | break;
273 |
274 | }
275 | }
276 | }
277 | else {
278 | for (var property in logic) {
279 | switch (logic[property]) {
280 | case 'ignore':
281 | break;
282 | case '=':
283 | results = results && (message.d[property] == trigger.value[property]);
284 | break;
285 | case '!=':
286 | results = results && (message.d[property] != trigger.value[property]);
287 | break;
288 | case '>':
289 | results = results && (message.d[property] > trigger.value[property]);
290 | break;
291 | case '>=':
292 | results = results && (message.d[property] >= trigger.value[property]);
293 | break;
294 | case '<':
295 | results = results && (message.d[property] < trigger.value[property]);
296 | break;
297 | case '<=':
298 | results = results && (message.d[property] <= trigger.value[property]);
299 | break;
300 | case 'between':
301 | results = results && (message.d[property] > trigger.value[property] && message.d[property] < trigger.value2[property]);
302 | break;
303 | case 'starts with':
304 | results = results && typeof message.d[property] != typeof undefined && message.d[property] != null && message.d[property].startsWith(trigger.value[property]);
305 | break;
306 | case 'ends with':
307 | results = results && typeof message.d[property] != typeof undefined && message.d[property] != null && message.d[property].endsWith(trigger.value[property]);
308 | break;
309 | case 'contains':
310 | results = results && typeof message.d[property] != typeof undefined && message.d[property] != null && message.d[property].indexOf(trigger.value[property]) != -1;
311 | break;
312 | case "equals":
313 | results = results && (message.d[property] == trigger.value[property]);
314 | break;
315 |
316 | }
317 | }
318 | }
319 |
320 | return results;
321 | }
322 |
323 | module.exports = EventCapturer;
--------------------------------------------------------------------------------
/typings/globals/rpio/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/fb972b28d215806c57280990833b6e7102012056/rpio/index.d.ts
3 | declare var rpio: Rpio;
4 |
5 | declare module 'rpio' {
6 | export = rpio;
7 | }
8 |
9 | interface Rpio {
10 | /**
11 | * Initialise the bcm2835 library. This will be called automatically by .open() using the default option values if not called explicitly.
12 | * @param options
13 | */
14 | init(options: RPIO.Options): void;
15 |
16 | /**
17 | * Open a pin for input or output. Valid modes are:
18 | * INPUT: pin is input (read-only).
19 | * OUTPUT: pin is output (read-write).
20 | * PWM: configure pin for hardware PWM.
21 | *
22 | * For input pins, option can be used to configure the internal pullup or pulldown resistors using options as described in the .pud() documentation below.
23 | *
24 | * For output pins, option defines the initial isMotionDetected of the pin, rather than having to issue a separate .write() call. This can be critical for devices which must have a stable value, rather than relying on the initial floating value when a pin is enabled for output but hasn't yet been configured with a value.
25 | * @param pin
26 | * @param mode
27 | * @param options
28 | */
29 | open(pin: number, mode: number, options?: number): void;
30 |
31 | /**
32 | * Switch a pin that has already been opened in one mode to a different mode.
33 | * This is provided primarily for performance reasons, as it avoids some of the setup work done by .open().
34 | * @param pin
35 | * @param mode
36 | */
37 | mode(pin: number, mode: number): void;
38 |
39 | /**
40 | * Read the current value of pin, returning either 1 (high) or 0 (low).
41 | * @param pin
42 | */
43 | read(pin: number): number;
44 |
45 | /**
46 | * Read length bits from pin into buffer as fast as possible. If length isn't specified it defaults to buffer.length.
47 | * @param pin
48 | * @param buffer
49 | * @param length
50 | */
51 | readbuf(pin: number, buffer: Buffer, length?: number): void;
52 |
53 | /**
54 | * Set the specified pin either high or low, using either the HIGH/LOW constants, or simply 1 or 0.
55 | * @param pin
56 | * @param value
57 | */
58 | write(pin: number, value: number): void;
59 |
60 | /**
61 | * Write length bits to pin from buffer as fast as possible. If length isn't specified it defaults to buffer.length.
62 |
63 | * @param pin
64 | * @param buffer
65 | * @param length
66 | */
67 | writebuf(pin: number, buffer: Buffer, length?: number): void;
68 |
69 | /**
70 | * Read the current isMotionDetected of the GPIO pad control for the specified GPIO group. On current models of Raspberry Pi there are three groups with corresponding defines:
71 | * PAD_GROUP_0_27: GPIO0 - GPIO27. Use this for the main GPIO header.
72 | * PAD_GROUP_28_45: GPIO28 - GPIO45. Use this to configure the P5 header.
73 | * PAD_GROUP_46_53: GPIO46 - GPIO53. Internal, you probably won't need this.
74 | *
75 | * The value returned will be a bit mask of the following defines:
76 | * PAD_SLEW_UNLIMITED: 0x10. Slew rate unlimited if set.
77 | * PAD_HYSTERESIS: 0x08. Hysteresis is enabled if set.
78 | *
79 | * The bottom three bits determine the drive current:
80 | * PAD_DRIVE_2mA: 0b000
81 | * PAD_DRIVE_4mA: 0b001
82 | * PAD_DRIVE_6mA: 0b010
83 | * PAD_DRIVE_8mA: 0b011
84 | * PAD_DRIVE_10mA: 0b100
85 | * PAD_DRIVE_12mA: 0b101
86 | * PAD_DRIVE_14mA: 0b110
87 | * PAD_DRIVE_16mA: 0b111
88 | *
89 | * @note Note that the pad control registers are not available via /dev/gpiomem, so you will need to use .init({gpiomem: false}) and run as root.
90 | * @param group
91 | */
92 | readpad(group: number): number;
93 |
94 | /**
95 | * Write control settings to the pad control for group. Uses the same defines as above for .readpad().
96 | * @param group
97 | * @param control
98 | */
99 | writepad(group: number, control: number): void;
100 |
101 | /**
102 | * Configure the pin's internal pullup or pulldown resistors, using the following isMotionDetected constants:
103 | * PULL_OFF: disable configured resistors.
104 | * PULL_DOWN: enable the pulldown resistor.
105 | * PULL_UP: enable the pullup resistor.
106 | *
107 | * @param pin
108 | * @param state
109 | */
110 | pud(pin: number, state: number): void;
111 |
112 | /**
113 | * Watch pin for changes and execute the callback cb() on events. cb() takes a single argument, the pin which triggered the callback.
114 | *
115 | * The optional direction argument can be used to watch for specific events:
116 | * POLL_LOW: poll for falling edge transitions to low.
117 | * POLL_HIGH: poll for rising edge transitions to high.
118 | * POLL_BOTH: poll for both transitions (the default).
119 | *
120 | * Due to hardware/kernel limitations we can only poll for changes, and the event detection only says that an event occurred, not which one. The poll interval is a 1ms setInterval() and transitions could come in between detecting the event and reading the value. Therefore this interface is only useful for events which transition slower than approximately 1kHz.
121 | *
122 | * To stop watching for pin changes, call .poll() again, setting the callback to null.
123 | * @param pin
124 | * @param cb
125 | * @param direction
126 | */
127 | poll(pin: number, cb: RPIO.CallbackFunction, direction?: number): void;
128 |
129 | /**
130 | * Reset pin to INPUT and clear any pullup/pulldown resistors and poll events.
131 | * @param pin
132 | */
133 | close(pin: number): void;
134 |
135 | // I²C
136 |
137 | /**
138 | * Assign pins 3 and 5 to i²c use. Until .i2cEnd() is called they won't be available for GPIO use.
139 | *
140 | * The pin assignments are:
141 | * Pin 3: SDA (Serial Data)
142 | * Pin 5: SCL (Serial Clock)
143 | */
144 | i2cBegin(): void;
145 |
146 | /**
147 | * Configure the slave address. This is between 0 - 0x7f, and it can be helpful to
148 | * run the i2cdetect program to figure out where your devices are if you are unsure.
149 | * @param address
150 | */
151 | i2cSetSlaveAddress(address: number): void;
152 |
153 | /**
154 | * Set the baud rate - directly set the speed in hertz.
155 | * @param baudRate
156 | */
157 | i2cSetBaudRate(baudRate: number): void;
158 |
159 | /**
160 | * Read from the i²c slave.
161 | * Function takes a buffer and optional length argument, defaulting to the length of the buffer if not specified.
162 | * @param buffer
163 | * @param length
164 | */
165 | i2cRead(buffer: Buffer, length?: number): void;
166 |
167 | /**
168 | * Write to the i²c slave.
169 | * Function takes a buffer and optional length argument, defaulting to the length of the buffer if not specified.
170 | * @param biffer
171 | * @param length
172 | */
173 | i2cWrite(biffer: Buffer, length?: number): void;
174 |
175 | /**
176 | * Set the baud rate - based on a divisor of the base 250MHz rate.
177 | * @param clockDivider
178 | */
179 | i2cSetClockDivider(clockDivider: number): void;
180 |
181 |
182 |
183 |
184 | /**
185 | * Turn off the i²c interface and return the pins to GPIO.
186 | */
187 | i2cEnd(): void;
188 |
189 | // PWM
190 |
191 | /**
192 | * Set the PWM refresh rate.
193 | * @param clockDivider: power-of-two divisor of the base 19.2MHz rate, with a maximum value of 4096 (4.6875kHz).
194 | */
195 | pwmSetClockDivider(clockDivider: number): void;
196 |
197 | /**
198 | * Set the PWM range for a pin. This determines the maximum pulse width.
199 | * @param pin
200 | * @param range
201 | */
202 | pwmSetRange(pin: number, range: number): void;
203 |
204 | /**
205 | * Set the PWM width for a pin.
206 | * @param pin
207 | * @param data
208 | */
209 | pwmSetData(pin: number, data: number): void;
210 |
211 | // SPI
212 |
213 | /**
214 | * Switch pins 119, 21, 23, 24 and 25 (GPIO7-GPIO11) to SPI mode
215 | *
216 | * Pin | Function
217 | * -----|----------
218 | * 19 | MOSI
219 | * 21 | MISO
220 | * 23 | SCLK
221 | * 24 | CE0
222 | * 25 | CE1
223 | */
224 | spiBegin(): void;
225 |
226 | /**
227 | * Choose which of the chip select / chip enable pins to control.
228 | *
229 | * Value | Pin
230 | * ------|---------------------
231 | * 0 | SPI_CE0 (24 / GPIO8)
232 | * 1 | SPI_CE1 (25 / GPIO7)
233 | * 2 | Both
234 | *
235 | * @param chip
236 | */
237 | spiChipSelect(cePin: number): void;
238 |
239 | /**
240 | * Commonly chip enable (CE) pins are active low, and this is the default.
241 | * If your device's CE pin is active high, use spiSetCSPolarity() to change the polarity.
242 | * @param cePin
243 | * @param polarity
244 | */
245 | spiSetCSPolarity(cePin: number, polarity: number): void;
246 |
247 | /**
248 | * Set the SPI clock speed with.
249 | * @param clockDivider: an even divisor of the base 250MHz rate ranging between 0 and 65536.
250 | */
251 | spiSetClockDivider(clockDivider: number): void;
252 |
253 | /**
254 | * Transfer data. Data is sent and received in 8-bit chunks via buffers which should be the same size.
255 | * @param txBuffer
256 | * @param rxBuffer
257 | * @param txLength
258 | */
259 | spiTransfer(txBuffer: Buffer, rxBuffer: Buffer, txLength: number): void;
260 |
261 | /**
262 | * Send data and do not care about the data coming back.
263 | * @param txBuffer
264 | * @param txLength
265 | */
266 | spiWrite(txBuffer: Buffer, txLength: number): void;
267 |
268 | /**
269 | * Release the pins back to general purpose use.
270 | */
271 | spiEnd(): void;
272 |
273 | // Misc
274 |
275 | /**
276 | * Sleep for n seconds.
277 | * @param n: number of seconds to sleep
278 | */
279 | sleep(n: number): void;
280 |
281 | /**
282 | * Sleep for n milliseconds.
283 | * @param n: number of milliseconds to sleep
284 | */
285 | msleep(n: number): void;
286 |
287 | /**
288 | * Sleep for n microseconds.
289 | * @param n: number of microseconds to sleep
290 | */
291 | usleep(n: number): void;
292 |
293 |
294 | // Constants:
295 |
296 | HIGH: number;
297 | LOW: number;
298 |
299 | INPUT: number;
300 | OUTPUT: number;
301 | PWM: number;
302 |
303 | PULL_OFF: number;
304 | PULL_DOWN: number;
305 | PULL_UP: number;
306 |
307 | PAD_GROUP_0_27: number;
308 | PAD_GROUP_28_45: number;
309 | PAD_GROUP_46_53: number;
310 |
311 | PAD_SLEW_UNLIMITED: number;
312 | PAD_HYSTERESIS: number;
313 |
314 | PAD_DRIVE_2mA: number;
315 | PAD_DRIVE_4mA: number;
316 | PAD_DRIVE_6mA: number;
317 | PAD_DRIVE_8mA: number;
318 | PAD_DRIVE_10mA: number;
319 | PAD_DRIVE_12mA: number;
320 | PAD_DRIVE_14mA: number;
321 | PAD_DRIVE_16mA: number;
322 |
323 | POLL_LOW: number;
324 | POLL_HIGH: number;
325 | POLL_BOTH: number;
326 |
327 | }
328 |
329 | declare namespace RPIO {
330 |
331 | interface Options {
332 |
333 | /**
334 | * There are two device nodes for GPIO access. The default is /dev/gpiomem which, when configured with gpio group access, allows users in that group to read/write directly to that device. This removes the need to run as root, but is limited to GPIO functions.
335 | * For non-GPIO functions (i²c, PWM, SPI) the /dev/mem device is required for full access to the Broadcom peripheral address range and the program needs to be executed as the root user (e.g. via sudo). If you do not explicitly call .init() when using those functions, the library will do it for you with gpiomem: false.
336 | * You may also need to use gpiomem: false if you are running on an older Linux kernel which does not support the gpiomem module.
337 | * rpio will throw an exception if you try to use one of the non-GPIO functions after already opening with /dev/gpiomem, as well as checking to see if you have the necessary permissions.
338 | *
339 | * Valid options:
340 | * true: use /dev/gpiomem for non-root but GPIO-only access
341 | * false: use /dev/mem for full access but requires root
342 | */
343 | gpiomem?: boolean;
344 |
345 | /**
346 | * There are two naming schemes when referring to GPIO pins:
347 | * By their physical header location: Pins 1 to 26 (A/B) or Pins 1 to 40 (A+/B+)
348 | * Using the Broadcom hardware map: GPIO 0-25 (B rev1), GPIO 2-27 (A/B rev2, A+/B+)
349 | *
350 | * Confusingly however, the Broadcom GPIO map changes between revisions, so for example P3 maps to GPIO0 on Model B Revision 1 models, but maps to GPIO2 on all later models.
351 | * This means the only sane default mapping is the physical layout, so that the same code will work on all models regardless of the underlying GPIO mapping.
352 | * If you prefer to use the Broadcom GPIO scheme for whatever reason (e.g. to use the P5 header pins on the Raspberry Pi 1 revision 2.0 model which aren't currently mapped to the physical layout), you can set mapping to gpio to switch to the GPIOxx naming.
353 | *
354 | * Valid options:
355 | * gpio: use the Broadcom GPIOxx naming
356 | * physical: use the physical P01-P40 header layou
357 | */
358 | mapping?: "gpio" | "physical";
359 | }
360 |
361 | interface CallbackFunction {
362 | /**
363 | * @param pin: The pin which triggered the callback.
364 | */
365 | (pin: number): void;
366 | }
367 | }
368 |
--------------------------------------------------------------------------------