sinricpro 2.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 14
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # SinricPro (NodeJs-SDK)
2
+
3
+ [![](https://img.shields.io/npm/v/sinricpro)](https://www.npmjs.com/package/sinricpro)
4
+ [![](https://img.shields.io/npm/dependency-version/sinricpro/dev/eslint)](https://www.npmjs.com/package/sinricpro)
5
+ [![](https://img.shields.io/bundlephobia/min/sinricpro)](https://www.npmjs.com/package/sinricpro)
6
+ [![](https://img.shields.io/github/languages/code-size/sinricpro/nodejs-sdk)](https://www.npmjs.com/package/sinricpro)
7
+
8
+ ### Installation
9
+
10
+ ```
11
+ npm install sinricpro
12
+ ```
13
+
14
+ ### Dependencies
15
+
16
+ - [websockets](https://www.npmjs.com/package/ws)
17
+
18
+ - [crypto](https://nodejs.org/api/crypto.html)
19
+
20
+ - [uuid](https://www.npmjs.com/package/uuid)
21
+
22
+ - [dgram]()
23
+
24
+ - [rxjs](https://www.npmjs.com/package/rxjs)
25
+
26
+ ### Basic example
27
+
28
+ ```javascript 1.8
29
+ const {
30
+ SinricPro,
31
+ SinricProActions,
32
+ raiseEvent,
33
+ eventNames,
34
+ SinricProUdp
35
+ } = require("../index"); // Use require('sinricpro'); if you are using NPM
36
+
37
+ const appKey = ""; // d89f1***-****-****-****-************
38
+ const secretKey = ""; // f44d1d31-1c19-****-****-9bc96c34b5bb-d19f42dd-****-****-****-************
39
+ const device1 = ""; // 5d7e7d96069e275ea9******
40
+ const device2 = ""; // 5d80ac5713fa175e99******
41
+ const deviceId = [device1, device2];
42
+
43
+ function setPowerState(deviceid, data) {
44
+ console.log(deviceid, data);
45
+ return true;
46
+ }
47
+
48
+ const callbacks = {
49
+ setPowerState
50
+ };
51
+
52
+ const sinricpro = new SinricPro(appKey, deviceId, secretKey, true);
53
+
54
+ SinricProActions(sinricpro, callbacks);
55
+
56
+ setInterval(() => {
57
+ raiseEvent(sinricpro, eventNames.powerState, device1, { state: "On" });
58
+ }, 2000);
59
+
60
+ // https://github.com/sinricpro/nodejs-sdk/blob/master/examples/simple-example/simple-example.js
61
+ ```
62
+
63
+ ### Advanced example
64
+
65
+ #### Add a credential file into your root folder (credential.js)
66
+
67
+ ```javascript 1.8
68
+ const credential = {
69
+ appkey: "",
70
+ secretKey: ""
71
+ };
72
+
73
+ const deviceIds = {
74
+ deviceId1: "",
75
+ deviceId2: "",
76
+ deviceId3: ""
77
+ };
78
+
79
+ // No need to edit the code below
80
+
81
+ let deviceIdT = [];
82
+
83
+ for (let key in deviceIds) {
84
+ if (deviceIds.hasOwnProperty(key)) {
85
+ deviceIdT.push(deviceIds[key]);
86
+ }
87
+ }
88
+
89
+ module.exports = {
90
+ appKey: credential.appkey,
91
+ secretKey: credential.secretKey,
92
+ deviceId: deviceIdT
93
+ };
94
+ ```
95
+
96
+ #### Example (app.js)
97
+
98
+ ```javascript
99
+ const { appKey, deviceId, secretKey } = require("../credentials");
100
+ const {
101
+ SinricPro,
102
+ SinricProActions,
103
+ raiseEvent,
104
+ eventNames,
105
+ SinricProUdp
106
+ } = require("../index");
107
+
108
+ function setPowerState(deviceid, data) {
109
+ console.log(deviceid, data);
110
+ return true;
111
+ }
112
+ function setPowerLevel(deviceid, data) {
113
+ console.log(deviceid, data);
114
+ return true;
115
+ }
116
+
117
+ function adjustPowerLevel(deviceid, data) {
118
+ console.log(deviceid, data);
119
+ return true;
120
+ }
121
+
122
+ function setColor(deviceid, data) {
123
+ console.log(deviceid, data);
124
+ return true;
125
+ }
126
+
127
+ function setRangeValue(deviceid, data) {
128
+ console.log(deviceid, data);
129
+ return true;
130
+ }
131
+ function setLockState(deviceid, data) {
132
+ console.log(deviceid, data);
133
+ return true;
134
+ }
135
+
136
+ function setBrightness(deviceid, data) {
137
+ console.log(deviceid, data);
138
+ return true;
139
+ }
140
+
141
+ function setVolume(deviceid, data) {
142
+ console.log(deviceid, data);
143
+ return true;
144
+ }
145
+
146
+ function adjustVolume(deviceid, data) {
147
+ console.log(deviceid, data);
148
+ return true;
149
+ }
150
+
151
+ function setMute(deviceid, data) {
152
+ console.log(deviceid, data);
153
+ return true;
154
+ }
155
+
156
+ const callbacks = {
157
+ setPowerState,
158
+ setPowerLevel,
159
+ adjustPowerLevel,
160
+ setColor,
161
+ setRangeValue,
162
+ setLockState,
163
+ setBrightness,
164
+ setVolume,
165
+ adjustVolume,
166
+ setMute
167
+ };
168
+
169
+ const sinricpro = new SinricPro(appKey, deviceId, secretKey, true);
170
+ SinricProActions(sinricpro, callbacks);
171
+
172
+ setInterval(() => {
173
+ // raiseEvent(sinricpro, eventNames.powerState, 'deviceId', { state: 'On' });
174
+ // raiseEvent(sinricpro, eventNames.setBrightness, 'deviceId', { brightness: 44 });
175
+ // raiseEvent(sinricpro, eventNames.powerLevel, 'deviceId', { powerLevel: 44 });
176
+ // raiseEvent(sinricpro, eventNames.color, 'DeviceId', { color: { b: 0, g: 0, r: 0 } });
177
+ // raiseEvent(sinricpro, eventNames.colorTemperature, 'Deviceid', { colorTemperature: 8 });
178
+ // raiseEvent(sinricpro, eventNames.doorBell, 'DeviceId', { state: 'pressed' });
179
+ // raiseEvent(sinricpro, eventNames.thermostatMode, 'DeviceId', { thermostatMode: 'AUTO' });
180
+ // raiseEvent(sinricpro, eventNames.rangvalue, 'DeviceId', { rangvalue: 3 });
181
+ // raiseEvent(sinricpro, eventNames.motion, 'DeviceId', { state: 'detected' });
182
+ // raiseEvent(sinricpro, eventNames.contact, 'DeviceId', { state: 'closed' });
183
+ // raiseEvent(sinricpro, eventNames.setVolume, 'DeviceId', { volume: 29 });
184
+ // raiseEvent(sinricpro, eventNames.selectInput, 'DeviceId', { input: 'HDMI' });
185
+ // raiseEvent(sinricpro, eventNames.media, 'DeviceId', { control: 'FastForward' });
186
+ // raiseEvent(sinricpro, eventNames.channel, 'DeviceId', { channel: { name: 'HBO' } });
187
+ // raiseEvent(sinricpro, eventNames.mode, 'DeviceId', { mode: 'MOVIE' });
188
+ // raiseEvent(sinricpro, eventNames.lock, 'DeviceId', { state: 'LOCKED' });
189
+ // raiseEvent(sinricpro, eventNames.mute, 'DeviceId', { mute: true });
190
+ }, 2000);
191
+ ```
package/index.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./lib/sinrcpro');
@@ -0,0 +1,192 @@
1
+ /*
2
+ * Copyright (c) 2019 Sinric. All rights reserved.
3
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
4
+ *
5
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
6
+ */
7
+
8
+ const { getSignature, verifySignature } = require('./signature');
9
+ const { powerState, powerLevel, powerLevelAdjust } = require('./contorllers/power_controller');
10
+ const { Brightness, BrightnessAdjust } = require('./contorllers/brightness_controller');
11
+ const { Color } = require('./contorllers/color_controller');
12
+ const { ColorTemperature } = require('./contorllers/color_temperature');
13
+ const { ThermoStatMode, ThermoStatTemperature, Lock } = require('./contorllers/sensors_controller');
14
+ const { RangeValue, RangeValueAdjust } = require('./contorllers/range_value_controller');
15
+ const { Volume, VolumeAdjust, Mute } = require('./contorllers/tv_controller');
16
+ const { ChangeChannel, SkipChannel, Media } = require('./contorllers/tv_controller');
17
+ const { Input } = require('./contorllers/tv_controller');
18
+ const { Bands, Mode, BandReset } = require('./contorllers/speaker_controller');
19
+ const { AdjustBands } = require('./contorllers/speaker_controller');
20
+
21
+ const jsonResponse = (client, defaultPayload, dValue) => {
22
+ const header = {
23
+ payloadVersion: 2,
24
+ signatureVersion: 1,
25
+ };
26
+
27
+ const payload = {
28
+ action: defaultPayload.action,
29
+ clientId: defaultPayload.clientId,
30
+ createdAt: Math.floor(new Date() / 1000),
31
+ deviceId: defaultPayload.deviceId,
32
+ message: 'OK',
33
+ replyToken: defaultPayload.replyToken,
34
+ success: true,
35
+ type: 'response',
36
+ value: dValue,
37
+ };
38
+
39
+ const signature = {
40
+ HMAC: getSignature(client, JSON.stringify(payload)),
41
+ };
42
+ return { header, payload, signature };
43
+ };
44
+
45
+ const handlePayload = (client, payload, signature, callbacks) => verifySignature(client, payload, signature)
46
+ .then((action) => {
47
+ /* eslint no-else-return: ["error", {allowElseIf: true}] */
48
+ if (action === 'setPowerState') {
49
+ return powerState(payload, callbacks)
50
+ .then((value) => jsonResponse(client, payload, value))
51
+ .catch((err) => {
52
+ console.log(err.message);
53
+ });
54
+ } else if (action === 'setPowerLevel') {
55
+ return powerLevel(payload, callbacks)
56
+ .then((value) => jsonResponse(client, payload, value))
57
+ .catch((err) => {
58
+ console.log(err.message);
59
+ });
60
+ } else if (action === 'adjustPowerLevel') {
61
+ return powerLevelAdjust(payload, callbacks)
62
+ .then((value) => jsonResponse(client, payload, value))
63
+ .catch((err) => {
64
+ console.log(err.message);
65
+ });
66
+ } else if (action === 'setBrightness') {
67
+ return Brightness(payload, callbacks)
68
+ .then((value) => jsonResponse(client, payload, value))
69
+ .catch((err) => {
70
+ console.log(err.message);
71
+ });
72
+ } else if (action === 'adjustBrightness') {
73
+ return BrightnessAdjust(payload, callbacks)
74
+ .then((value) => jsonResponse(client, payload, value))
75
+ .catch((err) => {
76
+ console.log(err.message);
77
+ });
78
+ } else if (action === 'setColor') {
79
+ return Color(payload, callbacks)
80
+ .then((value) => jsonResponse(client, payload, value))
81
+ .catch((err) => {
82
+ console.log(err.message);
83
+ });
84
+ } else if (action === 'setColorTemperature') {
85
+ return ColorTemperature(payload, callbacks)
86
+ .then((value) => jsonResponse(client, payload, value))
87
+ .catch((err) => {
88
+ console.log(err.message);
89
+ });
90
+ } else if (action === 'setThermostatMode') {
91
+ return ThermoStatMode(payload, callbacks)
92
+ .then((value) => jsonResponse(client, payload, value))
93
+ .catch((err) => {
94
+ console.log(err.message);
95
+ });
96
+ } else if (action === 'targetTemperature') {
97
+ return ThermoStatTemp(payload, callbacks)
98
+ .then((value) => jsonResponse(client, payload, value))
99
+ .catch((err) => {
100
+ console.log(err.message);
101
+ });
102
+ } else if (action === 'setRangeValue') {
103
+ return RangeValue(payload, callbacks)
104
+ .then((value) => jsonResponse(client, payload, value))
105
+ .catch((err) => {
106
+ console.log(err.message);
107
+ });
108
+ } else if (action === 'adjustRangeValue') {
109
+ return RangeValueAdjust(payload, callbacks)
110
+ .then((value) => jsonResponse(client, payload, value))
111
+ .catch((err) => {
112
+ console.log(err.message);
113
+ });
114
+ } else if (action === 'setVolume') {
115
+ return Volume(payload, callbacks)
116
+ .then((value) => jsonResponse(client, payload, value))
117
+ .catch((err) => {
118
+ console.log(err.message);
119
+ });
120
+ } else if (action === 'adjustVolume') {
121
+ return VolumeAdjust(payload, callbacks)
122
+ .then((value) => jsonResponse(client, payload, value))
123
+ .catch((err) => {
124
+ console.log(err.message);
125
+ });
126
+ } else if (action === 'selectInput') {
127
+ return Input(payload, callbacks)
128
+ .then((value) => jsonResponse(client, payload, value))
129
+ .catch((err) => {
130
+ console.log(err.message);
131
+ });
132
+ } else if (action === 'mediaControl') {
133
+ return Media(payload, callbacks)
134
+ .then((value) => jsonResponse(client, payload, value))
135
+ .catch((err) => {
136
+ console.log(err.message);
137
+ });
138
+ } else if (action === 'changeChannel') {
139
+ return ChangeChannel(payload, callbacks)
140
+ .then((value) => jsonResponse(client, payload, value))
141
+ .catch((err) => {
142
+ console.log(err.message);
143
+ });
144
+ } else if (action === 'skipChannels') {
145
+ return SkipChannel(payload, callbacks)
146
+ .then((value) => jsonResponse(client, payload, value))
147
+ .catch((err) => {
148
+ console.log(err.message);
149
+ });
150
+ } else if (action === 'setBands') {
151
+ return Bands(payload, callbacks)
152
+ .then((value) => jsonResponse(client, payload, value))
153
+ .catch((err) => {
154
+ console.log(err.message);
155
+ });
156
+ } else if (action === 'adjustBands') {
157
+ return AdjustBands(payload, callbacks)
158
+ .then((value) => jsonResponse(client, payload, value))
159
+ .catch((err) => {
160
+ console.log(err.message);
161
+ });
162
+ } else if (action === 'resetBands') {
163
+ return BandReset(payload, callbacks)
164
+ .then((value) => jsonResponse(client, payload, value))
165
+ .catch((err) => {
166
+ console.log(err.message);
167
+ });
168
+ } else if (action === 'setMode') {
169
+ return Mode(payload, callbacks)
170
+ .then((value) => jsonResponse(client, payload, value))
171
+ .catch((err) => {
172
+ console.log(err.message);
173
+ });
174
+ } else if (action === 'setLockState') {
175
+ return Lock(payload, callbacks)
176
+ .then((value) => jsonResponse(client, payload, value))
177
+ .catch((err) => {
178
+ console.log(err.message);
179
+ });
180
+ } else if (action === 'setMute') {
181
+ return Mute(payload, callbacks)
182
+ .then((value) => jsonResponse(client, payload, value))
183
+ .catch((err) => {
184
+ console.log(err.message);
185
+ });
186
+ }
187
+ return {};
188
+ })
189
+ .catch((err) => {
190
+ console.log(err.message);
191
+ });
192
+ module.exports = handlePayload;
@@ -0,0 +1,31 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricProData = require('../storage');
10
+
11
+ const Brightness = (payload, callback) => {
12
+ sinricProData.brightness = payload.value.brightness;
13
+ const resp = callback.setBrightness(payload.deviceId, sinricProData.brightness);
14
+ return new Promise((resolve, reject) => {
15
+ if (payload.value.brightness && resp) resolve(payload.value);
16
+ else reject(new Error('brightness is undefined'));
17
+ });
18
+ };
19
+
20
+ const BrightnessAdjust = (payload, callback) => {
21
+ sinricProData.brightness += payload.value.brightnessDelta;
22
+ if (sinricProData.brightness < 0) sinricProData.brightness = 0;
23
+ else if (sinricProData.brightness > 100) sinricProData.brightness = 100;
24
+ const resp = callback.adjustBrightness(payload.deviceId, sinricProData.brightness);
25
+ return new Promise((resolve, reject) => {
26
+ if (payload.value.brightness && resp) resolve({ brightness: sinricProData.brightness });
27
+ else reject(new Error('brightness is undefined'));
28
+ });
29
+ };
30
+
31
+ module.exports = { Brightness, BrightnessAdjust };
@@ -0,0 +1,20 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricProData = require('../storage');
10
+
11
+ const Color = (payload, callbacks) => {
12
+ sinricProData.color = payload.value.color;
13
+ const resp = callbacks.setColor(payload.deviceId, payload.value.color);
14
+ return new Promise((resolve, reject) => {
15
+ if (payload.value.color && resp) resolve(payload.value);
16
+ else reject(new Error('Colors undefined'));
17
+ });
18
+ };
19
+
20
+ module.exports = { Color };
@@ -0,0 +1,21 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricProData = require('../storage');
10
+
11
+ const ColorTemperature = (payload, callbacks) => {
12
+ sinricProData.colorTemperature = payload.value.colorTemperature;
13
+ const resp = callbacks.setColorTemperature(payload.deviceId, payload.value.colorTemperature);
14
+
15
+ return new Promise((resolve, reject) => {
16
+ if (payload.value.colorTemperature && resp) resolve(payload.value);
17
+ else reject(new Error('color temperature is undefined'));
18
+ });
19
+ };
20
+
21
+ module.exports = { ColorTemperature };
@@ -0,0 +1,45 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricProData = require('../storage');
10
+
11
+ const powerState = (payload, callbacks) => {
12
+ const resp = callbacks.setPowerState(payload.deviceId, payload.value.state);
13
+ return new Promise((resolve, reject) => {
14
+ if (payload.value.state && resp) {
15
+ resolve(payload.value);
16
+ } else {
17
+ reject(new Error('State is undefined'));
18
+ }
19
+ });
20
+ };
21
+
22
+ const powerLevel = (payload, callbacks) => {
23
+ sinricProData.powerLevel = payload.value.powerLevel;
24
+ const resp = callbacks.setPowerLevel(payload.deviceId, payload.value.powerLevel);
25
+ return new Promise((resolve, reject) => {
26
+ if (payload.value.powerLevel && resp) {
27
+ resolve(payload.value);
28
+ } else {
29
+ reject(new Error('powerLevel is undefined'));
30
+ }
31
+ });
32
+ };
33
+
34
+ const powerLevelAdjust = (payload, callbacks) => {
35
+ sinricProData.powerLevel += payload.value.powerLevelDelta;
36
+ if (sinricProData.powerLevel < 0) sinricProData.powerLevel = 0;
37
+ else if (sinricProData.powerLevel > 100) sinricProData.powerLevel = 100;
38
+ const resp = callbacks.adjustPowerLevel(payload.deviceId, sinricProData.powerLevel);
39
+ return new Promise((resolve, reject) => {
40
+ if (payload.value.powerLevelDelta && resp) resolve({ powerLevel: sinricProData.powerLevel });
41
+ else reject(new Error('PowerLevelDelta is 0 or undefined'));
42
+ });
43
+ };
44
+
45
+ module.exports = { powerState, powerLevel, powerLevelAdjust };
@@ -0,0 +1,32 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricProData = require('../storage');
10
+
11
+ const RangeValue = (payload, callbacks) => {
12
+ sinricProData.rangeValue = payload.value.rangeValue;
13
+ const resp = callbacks.setRangeValue(payload.deviceId, sinricProData.rangeValue);
14
+ return new Promise((resolve, reject) => {
15
+ if (payload.value.rangeValue && resp) resolve(payload.value);
16
+ else reject(new Error('RangeValue is undefined'));
17
+ });
18
+ };
19
+
20
+ const RangeValueAdjust = (payload, callbacks) => {
21
+ sinricProData.rangeValue += payload.value.rangeValueDelta;
22
+ if (sinricProData.rangeValue < 0) sinricProData.rangeValue = 0;
23
+ else if (sinricProData.rangeValue > 100) sinricProData.rangeValue = 100;
24
+ const resp = callbacks.adjustRangeValue(payload.deviceId, sinricProData.rangeValue);
25
+ return new Promise((resolve, reject) => {
26
+ if (payload.value.rangeValueDelta && resp) resolve({ rangeValue: sinricProData.rangeValue });
27
+ else reject(new Error('RangeValue undefined'));
28
+ });
29
+ };
30
+
31
+
32
+ module.exports = { RangeValue, RangeValueAdjust };
@@ -0,0 +1,36 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricProData = require('../storage');
10
+
11
+ const ThermoStatMode = (payload, callbacks) => {
12
+ sinricProData.thermostat.mode = payload.value.thermostatMode;
13
+ const resp = callbacks.setThermostatMode(payload.deviceId, sinricProData.thermostat.mode);
14
+ return new Promise((resolve, reject) => {
15
+ if (payload.value.thermostatMode && resp) resolve(payload.value);
16
+ else reject(new Error('Thermostat mode undefined'));
17
+ });
18
+ };
19
+ const ThermoStatTemperature = (payload, callbacks) => {
20
+ sinricProData.thermostat.temperature = payload.value.temperature;
21
+ const resp = callbacks.targetTemperature(payload.deviceId, sinricProData.thermostat.temperature);
22
+ return new Promise((resolve, reject) => {
23
+ if (payload.value.temperature && resp) resolve(payload.value);
24
+ else reject(new Error('Thermostat temperature undefined'));
25
+ });
26
+ };
27
+
28
+ const Lock = (payload, callbacks) => {
29
+ const resp = callbacks.setLockState(payload.deviceId, payload.value.state);
30
+ return new Promise((resolve, reject) => {
31
+ if (resp) resolve({ state: `${payload.value.state.toUpperCase()}ED` });
32
+ else reject(new Error('Set lock state error'));
33
+ });
34
+ };
35
+
36
+ module.exports = { ThermoStatMode, ThermoStatTemperature, Lock };
@@ -0,0 +1,50 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricData = require('../storage');
10
+
11
+ const Bands = (payload, callbacks) => {
12
+ sinricData.bands[0].level = payload.value.bands[0].level;
13
+ sinricData.bands[0].name = payload.value.bands[0].name;
14
+ const resp = callbacks.setBands(payload.deviceId, payload.value.bands);
15
+ return new Promise((resolve, reject) => {
16
+ if (resp === true) resolve(payload.value);
17
+ else reject(new Error('Callback failed'));
18
+ });
19
+ };
20
+
21
+ const Mode = (payload, callbacks) => {
22
+ const resp = callbacks.setMode(payload.deviceId, payload.value.mode);
23
+ return new Promise((resolve, reject) => {
24
+ if (resp) resolve(payload.value);
25
+ else reject(new Error('Mode undefined'));
26
+ });
27
+ };
28
+
29
+ const BandReset = (payload, callbacks) => {
30
+ const resp = callbacks.resetBands(payload.deviceId, payload.value);
31
+ return new Promise((resolve, reject) => {
32
+ if (resp) resolve(payload.value);
33
+ else reject(new Error('Rest Bands Failed'));
34
+ });
35
+ };
36
+
37
+ const AdjustBands = (payload, callbacks) => {
38
+ if (payload.value.bands[0].levelDelta) {
39
+ if (sinricData.bands[0].levelDirection === 'UP') sinricData.bands[0].level += payload.value.bands[0].levelDelta;
40
+ else if (sinricData.bands[0].levelDirection === 'DOWN') sinricData.bands[0].level -= payload.value.bands[0].levelDelta;
41
+ }
42
+ const resp = callbacks.adjustBands(payload.deviceId, sinricData.bands);
43
+ return new Promise((resolve, reject) => {
44
+ if (resp) resolve(payload.value, { bands: [{ level: sinricData.bands[0].level, name: sinricData.bands[0].name }] });
45
+ else reject(new Error('Rest Bands Failed'));
46
+ });
47
+ };
48
+ module.exports = {
49
+ Bands, Mode, BandReset, AdjustBands,
50
+ };
@@ -0,0 +1,76 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const sinricProData = require('../storage');
10
+
11
+ const Volume = (payload, callbacks) => {
12
+ sinricProData.volume = payload.value.volume;
13
+ const resp = callbacks.setVolume(payload.deviceId, sinricProData.volume);
14
+ return new Promise((resolve, reject) => {
15
+ if (payload.value.volume && resp) resolve(payload.value);
16
+ else reject(new Error('Volume undefined'));
17
+ });
18
+ };
19
+
20
+ const VolumeAdjust = (payload, callbacks) => {
21
+ sinricProData.volume += payload.value.volume;
22
+ if (sinricProData.volume > 100) sinricProData.volume = 100;
23
+ else if (sinricProData.volume < 0) sinricProData.volume = 0;
24
+ const resp = callbacks.adjustVolume(payload.deviceId, sinricProData.volume);
25
+ return new Promise((resolve, reject) => {
26
+ if (payload.value.volume && resp) resolve({ volume: sinricProData.volume });
27
+ else reject(new Error('Volume undefined'));
28
+ });
29
+ };
30
+
31
+
32
+ const Mute = (payload, callbacks) => {
33
+ const resp = callbacks.setMute(payload.deviceId, payload.value.mute);
34
+ return new Promise((resolve, reject) => {
35
+ if ((payload.value.mute === true || payload.value.mute === false) && resp) resolve(payload.value);
36
+ else reject(new Error('Mute undefined'));
37
+ });
38
+ };
39
+
40
+ const Input = (payload, callbacks) => {
41
+ sinricProData.input = payload.value.input;
42
+ const resp = callbacks.selectInput(payload.deviceId, payload.value.input);
43
+ return new Promise((resolve, reject) => {
44
+ if (payload.value.input && resp) resolve(payload.value);
45
+ else reject(new Error('Input undefined'));
46
+ });
47
+ };
48
+
49
+ const Media = (payload, callbacks) => {
50
+ const resp = callbacks.mediaControl(payload.deviceId, payload.value.control);
51
+ return new Promise((resolve, reject) => {
52
+ if (payload.value.control && resp) resolve(payload.value);
53
+ else reject(new Error('Control undefined'));
54
+ });
55
+ };
56
+
57
+ const ChangeChannel = (payload, callbacks) => {
58
+ const channel = payload.value.channel.name ?? payload.value.channel.number;
59
+ const resp = callbacks.changeChannel(payload.deviceId, channel);
60
+ return new Promise((resolve, reject) => {
61
+ if (channel && resp) resolve(payload.value);
62
+ else reject(new Error('Channel name undefined'));
63
+ });
64
+ };
65
+
66
+ const SkipChannel = (payload, callbacks) => {
67
+ const resp = callbacks.skipChannels(payload.deviceId, payload.value.channelCount);
68
+ return new Promise((resolve, reject) => {
69
+ if (payload.value.channelCount && resp) resolve(payload.value);
70
+ else reject(new Error('Channel count undefined'));
71
+ });
72
+ };
73
+
74
+ module.exports = {
75
+ Volume, VolumeAdjust, Mute, Input, Media, ChangeChannel, SkipChannel,
76
+ };
@@ -0,0 +1,98 @@
1
+
2
+ /*
3
+ * Copyright (c) 2019 Sinric. All rights reserved.
4
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
5
+ *
6
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
7
+ */
8
+
9
+ const uuidv4 = require('uuid/v4');
10
+ const { RateLimiterMemory, BurstyRateLimiter } = require('rate-limiter-flexible');
11
+ const { getSignature } = require('../signature');
12
+
13
+ /*
14
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
15
+ * !! !!
16
+ * !! WARNING: DON'T TOUCH ! !!
17
+ * !! ====================== !!
18
+ * !! PLEASE DO NOT MODIFY ANY OF THESE SETTINGS HERE !!
19
+ * !! THIS IS FOR INTERNAL CONFIGURATION ONLY !!
20
+ * !! SINRIC PRO MIGHT NOT WORK IF YOU MODIFY THIS !!
21
+ * !! !!
22
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
23
+ */
24
+
25
+ const burstyLimiter = new BurstyRateLimiter(
26
+ new RateLimiterMemory({
27
+ points: 1,
28
+ duration: 60,
29
+ }),
30
+ new RateLimiterMemory({
31
+ keyPrefix: 'burst',
32
+ points: 10,
33
+ duration: 60,
34
+ }),
35
+ );
36
+
37
+ // @TODO resteBands
38
+
39
+ const eventNames = {
40
+ powerState: 'setPowerState',
41
+ setBrightness: 'setBrightness',
42
+ powerLevel: 'setPowerLevel',
43
+ color: 'setColor',
44
+ colorTemperature: 'setColorTemperature',
45
+ doorBell: 'DoorbellPress',
46
+ thermostatMode: 'setThermostatMode',
47
+ rangvalue: 'setRangeValue',
48
+ motion: 'motion',
49
+ contact: 'setContactState',
50
+ setVolume: 'setVolume',
51
+ selectInput: 'selectInput',
52
+ media: 'mediaControl',
53
+ channel: 'changeChannel',
54
+ mode: 'setMode',
55
+ lock: 'setLockState',
56
+ mute: 'setMute',
57
+ currentTemperature: 'currentTemperature',
58
+ };
59
+
60
+ const actionArr = ['setPowerState', 'setBrightness', 'setPowerLevel', 'setColor', 'setColorTemperature', 'DoorbellPress', 'currentTemperature'];
61
+
62
+ const getJson = (client, eventName, deviceId, value) => {
63
+ const header = {
64
+ payloadVersion: 2,
65
+ signatureVersion: 1,
66
+ };
67
+ const payload = {
68
+ action: eventName,
69
+ cause: {
70
+ type: 'PHYSICAL_INTERACTION',
71
+ },
72
+ createdAt: Math.round(new Date() / 1000),
73
+ deviceId,
74
+ replyToken: uuidv4(),
75
+ type: 'event',
76
+ value,
77
+ };
78
+ const signature = {
79
+ HMAC: getSignature(client, JSON.stringify(payload)),
80
+ };
81
+
82
+ return ({ header, payload, signature });
83
+ };
84
+
85
+ const raiseEvent = async (client, eventName, deviceId, value) => {
86
+ if (actionArr.includes(eventName)) {
87
+ try {
88
+ await burstyLimiter.consume('queue');
89
+ client.send(JSON.stringify(getJson(client, eventName, deviceId, value)));
90
+ } catch (rlRejected) {
91
+ console.log('Too many events!');
92
+ }
93
+ } else {
94
+ console.log('Invalid Event');
95
+ }
96
+ };
97
+
98
+ module.exports = { raiseEvent, eventNames };
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright (c) 2019 Sinric. All rights reserved.
3
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
4
+ *
5
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
6
+ */
7
+
8
+ const crypto = require('crypto');
9
+
10
+ const getSignature = (client, message) => crypto
11
+ .createHmac('sha256', client.getSecretKey)
12
+ .update(message)
13
+ .digest('base64');
14
+
15
+ const verifySignature = (client, payload, signature) => {
16
+ const localSignature = getSignature(client, JSON.stringify(payload));
17
+ return new Promise((resolve, reject) => {
18
+ if (signature === localSignature) {
19
+ resolve(payload.action);
20
+ } else {
21
+ reject(new Error("Signatures didn't match"));
22
+ }
23
+ });
24
+ };
25
+
26
+ module.exports = { getSignature, verifySignature };
@@ -0,0 +1,122 @@
1
+ /*
2
+ * Copyright (c) 2019 Sinric. All rights reserved.
3
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
4
+ *
5
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
6
+ *
7
+ */
8
+ const Websocket = require("ws");
9
+ const rx = require("rxjs");
10
+
11
+ const callbackHandler = require("./cbhandler");
12
+ const { raiseEvent, eventNames } = require("./events/event_handler");
13
+ const SinricProUdp = require("./sinricproudp");
14
+
15
+ const VERSION = "2.2.2";
16
+
17
+ class SinricPro extends Websocket {
18
+ constructor(appkey, deviceids, secretKey, restoreStates) {
19
+ super("ws://ws.sinric.pro", {
20
+ headers: {
21
+ appkey,
22
+ deviceids: deviceids.join(";"),
23
+ platform: "nodejs",
24
+ version: VERSION,
25
+ restoredevicestates: restoreStates,
26
+ },
27
+ });
28
+ this._secretKey = secretKey;
29
+ }
30
+
31
+ get getSecretKey() {
32
+ return this._secretKey;
33
+ }
34
+
35
+ set setSecretKey(key) {
36
+ this._secretKey = key;
37
+ }
38
+ }
39
+
40
+ const SinricProActions = (client, callbacks) => {
41
+ client.on("open", () => {
42
+ console.log("Connected to Sinric Pro");
43
+ });
44
+
45
+ client.on("message", (data) => {
46
+ const parsedData = JSON.parse(data);
47
+
48
+ if (parsedData.timestamp) {
49
+ if (Math.floor(new Date() / 1000) - parsedData.timestamp > 60000) {
50
+ console.log("Timestamp is not in sync");
51
+ } else console.log("TimeStamp is in sync");
52
+ } else {
53
+ const response = callbackHandler(
54
+ client,
55
+ parsedData.payload,
56
+ parsedData.signature.HMAC,
57
+ callbacks,
58
+ );
59
+ response
60
+ .then((res) => {
61
+ client.send(JSON.stringify(res));
62
+ })
63
+ .catch((err) => {
64
+ console.log(err.message);
65
+ });
66
+ }
67
+ });
68
+
69
+ client.on("close", () => {
70
+ if (callbacks.onDisconnect) {
71
+ callbacks.onDisconnect();
72
+ }
73
+ });
74
+ };
75
+
76
+ const SinricProActionsObservable = (client, callbacks) => new rx.Observable((observer) => {
77
+ client.on("open", () => {
78
+ console.log("Connected");
79
+ });
80
+
81
+ client.on("message", (data) => {
82
+ const parsedData = JSON.parse(data);
83
+ if (parsedData.timestamp) {
84
+ if (Math.floor(new Date() / 1000) - parsedData.timestamp > 60000) {
85
+ console.log("Timestamp is not in sync");
86
+ } else console.log("TimeStamp is in sync");
87
+ } else {
88
+ const response = callbackHandler(
89
+ client,
90
+ parsedData.payload,
91
+ parsedData.signature.HMAC,
92
+ callbacks,
93
+ );
94
+ response
95
+ .then((res) => {
96
+ observer.next(res);
97
+ client.send(JSON.stringify(res));
98
+ })
99
+ .catch((err) => {
100
+ observer.error(err.message);
101
+ console.log(err.message);
102
+ });
103
+ }
104
+ });
105
+
106
+ client.on("close", () => {
107
+ observer.complete();
108
+ if (callbacks.onDisconnect) {
109
+ callbacks.onDisconnect();
110
+ }
111
+ console.log("Disconnected");
112
+ });
113
+ });
114
+
115
+ module.exports = {
116
+ SinricPro,
117
+ SinricProActions,
118
+ SinricProActionsObservable,
119
+ raiseEvent,
120
+ eventNames,
121
+ SinricProUdp,
122
+ };
@@ -0,0 +1,60 @@
1
+ /*
2
+ * Copyright (c) 2019 Sinric. All rights reserved.
3
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
4
+ *
5
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
6
+ */
7
+
8
+ const SocketUdp = require('dgram');
9
+
10
+ const callbackHandler = require('./cbhandler');
11
+
12
+ class SinricProUdp {
13
+ get getSecretKey() {
14
+ return this._secretKey;
15
+ }
16
+
17
+ constructor(deviceids, secretKey) {
18
+ this._multicastAddress = '224.9.9.9';
19
+ this._multicastPort = 3333;
20
+ this._deviceIds = deviceids;
21
+ this._secretKey = secretKey;
22
+ this._multisocket = SocketUdp.createSocket({
23
+ type: 'udp4',
24
+ reuseAddr: true,
25
+ });
26
+ this._multisocket.bind(this._multicastPort, this._multicastAddress);
27
+
28
+ this.begin = (callbacks) => {
29
+ this._multisocket.on('listening', () => {
30
+ this._multisocket.addMembership(this._multicastAddress);
31
+ const address = this._multisocket.address();
32
+ console.log(
33
+ `Offline support started on : ${address.address}:${this._multicastPort}`,
34
+ );
35
+ });
36
+
37
+ this._multisocket.on('message', (message, rinfo) => {
38
+ const response = callbackHandler(
39
+ this,
40
+ JSON.parse(message).payload,
41
+ JSON.parse(message).signature.HMAC,
42
+ callbacks,
43
+ );
44
+ response
45
+ .then((res) => {
46
+ this._multisocket.send(
47
+ JSON.stringify(res),
48
+ rinfo.port,
49
+ rinfo.address,
50
+ );
51
+ })
52
+ .catch((err) => {
53
+ console.log(err.message);
54
+ });
55
+ });
56
+ };
57
+ }
58
+ }
59
+
60
+ module.exports = SinricProUdp;
package/lib/storage.js ADDED
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (c) 2019 Sinric. All rights reserved.
3
+ * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
4
+ *
5
+ * This file is part of the Sinric Pro (https://github.com/sinricpro/)
6
+ */
7
+ let data = {
8
+ powerLevel: 0,
9
+ brightness: 0,
10
+ color: {
11
+ r: 0,
12
+ g: 0,
13
+ b: 0,
14
+ },
15
+ lockState: '',
16
+ thermostat: {
17
+ mode: '',
18
+ temperature: 0
19
+ },
20
+ rangeValue: 0,
21
+ volume: 0,
22
+ colorTemperature: 0,
23
+ bands: [
24
+ {
25
+ level: 0,
26
+ name: '',
27
+ },
28
+ ],
29
+ };
30
+
31
+ module.exports = data;
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "sinricpro",
3
+ "version": "2.2.7",
4
+ "description": "Sinric Pro Nodejs SDK",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "lint": "eslint --fix ./"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/sinricpro/nodejs-sdk.git"
13
+ },
14
+ "author": "Dhanush",
15
+ "license": "ISC",
16
+ "bugs": {
17
+ "url": "https://github.com/sinricpro/nodejs-sdk/issues"
18
+ },
19
+ "homepage": "https://github.com/sinricpro/nodejs-sdk#readme",
20
+ "dependencies": {
21
+ "dgram": "^1.0.1",
22
+ "leaky-bucket": "^3.0.4",
23
+ "process": "^0.11.10",
24
+ "rate-limiter-flexible": "^2.2.1",
25
+ "rxjs": "^6.6.3",
26
+ "uuid": "^3.3.3",
27
+ "ws": "^7.4.2"
28
+ },
29
+ "keywords": [
30
+ "sinricpro",
31
+ "sinric"
32
+ ],
33
+ "devDependencies": {
34
+ "eslint": "^6.8.0",
35
+ "eslint-config-airbnb-base": "^14.0.0",
36
+ "eslint-config-standard": "^14.1.0",
37
+ "eslint-plugin-import": "^2.18.2",
38
+ "eslint-plugin-node": "^10.0.0",
39
+ "eslint-plugin-promise": "^4.2.1",
40
+ "eslint-plugin-standard": "^4.0.1"
41
+ }
42
+ }