node-red-contrib-yandex-station-management 0.3.3 → 0.3.6
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/lib/stationHelper.js +52 -0
- package/nodes/get.js +8 -34
- package/nodes/in.js +3 -37
- package/nodes/yandex-login.js +154 -119
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class stationHelper {
|
|
4
|
+
|
|
5
|
+
static preparePayload(node, message) {
|
|
6
|
+
let payload = {};
|
|
7
|
+
if (node.output == 'status') {
|
|
8
|
+
payload = { 'payload': message }
|
|
9
|
+
} else if (node.output == 'homekit') {
|
|
10
|
+
let playing = false;
|
|
11
|
+
if (typeof(message.playing) !== 'undefined') {
|
|
12
|
+
playing = message.playing;
|
|
13
|
+
}
|
|
14
|
+
if (node.homekitFormat == 'speaker') {
|
|
15
|
+
let subtitle = 'No Artist';
|
|
16
|
+
let title = 'No Track Name';
|
|
17
|
+
|
|
18
|
+
if (typeof(message.playerState) !== 'undefined') {
|
|
19
|
+
let playerState = message.playerState;
|
|
20
|
+
if (typeof(playerState.subtitle) !== 'undefined') {
|
|
21
|
+
subtitle = playerState.subtitle;
|
|
22
|
+
}
|
|
23
|
+
if (typeof(playerState.title) !== 'undefined') {
|
|
24
|
+
title = playerState.title;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let ConfiguredName = `${subtitle} - ${title}`;
|
|
29
|
+
if (ConfiguredName.length > 64) {
|
|
30
|
+
ConfiguredName = title.length <= 64 ? title : title.substr(0, 61) + `...`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
payload = {
|
|
34
|
+
'payload': {
|
|
35
|
+
'CurrentMediaState': (playing) ? 0 : 1,
|
|
36
|
+
'ConfiguredName': ConfiguredName
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} else if (node.homekitFormat == 'tv') {
|
|
40
|
+
payload = {
|
|
41
|
+
'payload': {
|
|
42
|
+
'Active': (playing) ? 1 : 0
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return payload;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = stationHelper;
|
package/nodes/get.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
module.exports = function(RED) {
|
|
2
|
+
const stationHelper = require('../lib/stationHelper.js');
|
|
3
|
+
|
|
2
4
|
function AliceLocalGetNode(config) {
|
|
3
5
|
RED.nodes.createNode(this,config);
|
|
4
6
|
let node = this;
|
|
@@ -16,43 +18,15 @@ module.exports = function(RED) {
|
|
|
16
18
|
node.log(text);
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
|
-
function preparePayload(message,inputMsg){
|
|
20
|
-
//let payload = {};
|
|
21
|
-
if (node.output == 'status') {
|
|
22
|
-
inputMsg.payload = message;
|
|
23
|
-
} else if (node.output == 'homekit') {
|
|
24
|
-
try {
|
|
25
|
-
if (node.homekitFormat == 'speaker') {
|
|
26
|
-
let ConfiguredName = `${(message.playerState.subtitle) ? message.playerState.subtitle : 'No Artist'} - ${(message.playerState.title) ? message.playerState.title : 'No Track Name'}`;
|
|
27
|
-
let title = `${message.playerState.title}`;
|
|
28
|
-
if (ConfiguredName.length > 64 && title.length > 0 && title.length <= 64) {
|
|
29
|
-
ConfiguredName = title;
|
|
30
|
-
} else {
|
|
31
|
-
ConfiguredName = title.substr(0, 61) + `...`;
|
|
32
|
-
}
|
|
33
|
-
(message.playerState)? inputMsg.payload = {
|
|
34
|
-
"CurrentMediaState": (message.playing) ? 0 : 1,
|
|
35
|
-
"ConfiguredName": ConfiguredName
|
|
36
|
-
} :inputMsg.payload = {
|
|
37
|
-
"CurrentMediaState": (message.playing) ? 0 : 1,
|
|
38
|
-
"ConfiguredName": `No Artist - No Track Name`
|
|
39
|
-
}
|
|
40
|
-
}else if (node.homekitFormat == 'tv') {
|
|
41
|
-
inputMsg.payload = {
|
|
42
|
-
"Active": (message.playing) ? 1 : 0
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
} catch (error) {
|
|
47
|
-
debugMessage(`Error while preparing payload: `+ e);
|
|
48
|
-
}
|
|
49
21
|
|
|
22
|
+
function _preparePayload(message, inputMsg) {
|
|
23
|
+
let prepare = stationHelper.preparePayload(node, message);
|
|
24
|
+
if (typeof(prepare.payload) !== 'undefined') {
|
|
25
|
+
inputMsg.payload = prepare.payload;
|
|
50
26
|
}
|
|
51
|
-
|
|
52
|
-
|
|
27
|
+
return inputMsg;
|
|
53
28
|
}
|
|
54
29
|
|
|
55
|
-
|
|
56
30
|
node.onStatus = function(data) {
|
|
57
31
|
if (data) {
|
|
58
32
|
node.status({fill: `${data.color}`,shape:"dot",text: `${data.text}`});
|
|
@@ -61,7 +35,7 @@ module.exports = function(RED) {
|
|
|
61
35
|
}
|
|
62
36
|
node.onInput = function(msg, send, done){
|
|
63
37
|
debugMessage('current state: ' + JSON.stringify(node.lastState));
|
|
64
|
-
( 'aliceState' in node.lastState )?node.send(
|
|
38
|
+
( 'aliceState' in node.lastState )?node.send(_preparePayload(node.lastState,msg)):node.send(msg)
|
|
65
39
|
}
|
|
66
40
|
node.onMessage = function(message){
|
|
67
41
|
node.lastState = message;
|
package/nodes/in.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
module.exports = function(RED) {
|
|
2
|
+
const stationHelper = require('../lib/stationHelper.js');
|
|
3
|
+
|
|
2
4
|
function AliceLocalInNode(config) {
|
|
3
5
|
RED.nodes.createNode(this,config);
|
|
4
6
|
let node = this;
|
|
@@ -20,42 +22,6 @@ module.exports = function(RED) {
|
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
function preparePayload(message){
|
|
25
|
-
let payload = {};
|
|
26
|
-
if (node.output == 'status') {
|
|
27
|
-
payload = {'payload': message}
|
|
28
|
-
} else if (node.output == 'homekit') {
|
|
29
|
-
try {
|
|
30
|
-
if (node.homekitFormat == 'speaker') {
|
|
31
|
-
let ConfiguredName = `${(message.playerState.subtitle) ? message.playerState.subtitle : 'No Artist'} - ${(message.playerState.title) ? message.playerState.title : 'No Track Name'}`;
|
|
32
|
-
let title = `${message.playerState.title}`;
|
|
33
|
-
if (ConfiguredName.length > 64 && title.length > 0 && title.length <= 64) {
|
|
34
|
-
ConfiguredName = title;
|
|
35
|
-
} else {
|
|
36
|
-
ConfiguredName = title.substr(0, 61) + `...`;
|
|
37
|
-
}
|
|
38
|
-
(message.playerState)? payload = {'payload': {
|
|
39
|
-
"CurrentMediaState": (message.playing) ? 0 : 1,
|
|
40
|
-
"ConfiguredName": ConfiguredName
|
|
41
|
-
} }:payload = {'payload': {
|
|
42
|
-
"CurrentMediaState": (message.playing) ? 0 : 1,
|
|
43
|
-
"ConfiguredName": `No Artists - No Track Name`
|
|
44
|
-
} }
|
|
45
|
-
}else if (node.homekitFormat == 'tv') {
|
|
46
|
-
payload = {'payload': {
|
|
47
|
-
"Active": (message.playing) ? 1 : 0
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
} catch(e) {
|
|
52
|
-
debugMessage(`Error while preparing payload: `+ e)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
return payload;
|
|
57
|
-
|
|
58
|
-
}
|
|
59
25
|
function sendMessage(message){
|
|
60
26
|
//debugMessage(JSON.stringify(message));
|
|
61
27
|
if (node.uniqueFlag && node.output == 'homekit') {
|
|
@@ -71,7 +37,7 @@ module.exports = function(RED) {
|
|
|
71
37
|
}
|
|
72
38
|
node.onMessage = function(data){
|
|
73
39
|
//debugMessage(JSON.stringify(data));
|
|
74
|
-
sendMessage(preparePayload(data));
|
|
40
|
+
sendMessage(stationHelper.preparePayload(node, data));
|
|
75
41
|
}
|
|
76
42
|
node.onStatus = function(data) {
|
|
77
43
|
if (data) {
|
package/nodes/yandex-login.js
CHANGED
|
@@ -18,27 +18,32 @@ module.exports = function(RED) {
|
|
|
18
18
|
node.readyList = [];
|
|
19
19
|
node.activeStationList = [];
|
|
20
20
|
//node.skipCloudDevices = false;
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
|
|
23
23
|
node.on('stopListening', onStopListening);
|
|
24
24
|
node.on('startPlay', onStartPlay);
|
|
25
25
|
node.on('stopPlay', onStopPlay);
|
|
26
26
|
node.on('setVolume', onSetVolume);
|
|
27
27
|
node.on('deviceReady', onDeviceReady);
|
|
28
28
|
node.setMaxListeners(0)
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
function debugMessage(text){
|
|
31
31
|
if (node.debugFlag) {
|
|
32
|
-
|
|
32
|
+
try {
|
|
33
|
+
node.log(text);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
node.log(error)
|
|
36
|
+
}
|
|
37
|
+
|
|
33
38
|
}
|
|
34
39
|
}
|
|
35
|
-
|
|
40
|
+
|
|
36
41
|
let registrationBuffer = [];
|
|
37
|
-
|
|
42
|
+
|
|
38
43
|
function deviceListProcessing(deviceList) {
|
|
39
44
|
deviceList.forEach(device => {
|
|
40
45
|
if (device.address && device.port ) {
|
|
41
|
-
|
|
46
|
+
|
|
42
47
|
if (node.readyList.find(item => item.id == device.id)){
|
|
43
48
|
//debugMessage('skipping');
|
|
44
49
|
} else {
|
|
@@ -54,23 +59,23 @@ module.exports = function(RED) {
|
|
|
54
59
|
|
|
55
60
|
async function getDevices(token)
|
|
56
61
|
{
|
|
57
|
-
let options =
|
|
58
|
-
{
|
|
62
|
+
let options =
|
|
63
|
+
{
|
|
59
64
|
method: 'GET',
|
|
60
65
|
url: 'https://quasar.yandex.net/glagol/device_list',
|
|
61
|
-
headers:
|
|
62
|
-
{
|
|
66
|
+
headers:
|
|
67
|
+
{
|
|
63
68
|
'Content-Type': 'application/json',
|
|
64
|
-
'Authorization': 'Oauth ' + token
|
|
65
|
-
}
|
|
69
|
+
'Authorization': 'Oauth ' + token
|
|
70
|
+
}
|
|
66
71
|
};
|
|
67
|
-
// вариант для снижения частоты запросов на серверы ЯНдекса для обновления списка устройств. Требует тестирования.
|
|
72
|
+
// вариант для снижения частоты запросов на серверы ЯНдекса для обновления списка устройств. Требует тестирования.
|
|
68
73
|
/* if (node.skipCloudDevices) {
|
|
69
74
|
discoverDevices(node.deviceList)
|
|
70
75
|
.then(() => {
|
|
71
76
|
//debugMessage(`calling processing for ${node.deviceList.length} devices`);
|
|
72
77
|
deviceListProcessing(node.deviceList)
|
|
73
|
-
|
|
78
|
+
|
|
74
79
|
});
|
|
75
80
|
return node.deviceList;
|
|
76
81
|
} */
|
|
@@ -91,7 +96,7 @@ module.exports = function(RED) {
|
|
|
91
96
|
if (result != 2 && result != undefined) {
|
|
92
97
|
registrationBuffer.splice(registrationBuffer.indexOf(bufferStation,1));
|
|
93
98
|
}
|
|
94
|
-
|
|
99
|
+
|
|
95
100
|
}
|
|
96
101
|
node.activeStationList.push({ 'name': device.name, 'id': device.id, 'platform': device.platform, 'address': device.address, 'port': device.port});
|
|
97
102
|
});
|
|
@@ -102,13 +107,13 @@ module.exports = function(RED) {
|
|
|
102
107
|
.then(() => {
|
|
103
108
|
//debugMessage(`calling processing for ${node.deviceList.length} devices`);
|
|
104
109
|
deviceListProcessing(node.deviceList)
|
|
105
|
-
|
|
110
|
+
|
|
106
111
|
});
|
|
107
112
|
//debugMessage(node.id);
|
|
108
113
|
return node.deviceList;
|
|
109
114
|
} catch (error) {
|
|
110
115
|
debugMessage(`Error while searching: ${error}`);
|
|
111
|
-
}
|
|
116
|
+
}
|
|
112
117
|
|
|
113
118
|
})
|
|
114
119
|
.catch(function (err) {
|
|
@@ -126,7 +131,6 @@ module.exports = function(RED) {
|
|
|
126
131
|
await mDnsSd.discover({
|
|
127
132
|
name: '_yandexio._tcp.local'
|
|
128
133
|
}).then((result) => {
|
|
129
|
-
debugMessage(`MDNS. Found ${result.length} devices`);
|
|
130
134
|
node.emit('refreshHttpDNS', result);
|
|
131
135
|
if (result.length != 0){
|
|
132
136
|
for (const device of deviceList) {
|
|
@@ -147,15 +151,15 @@ module.exports = function(RED) {
|
|
|
147
151
|
} catch(e) {
|
|
148
152
|
debugMessage(`Error searching hostname in mDNS answer`)
|
|
149
153
|
}
|
|
150
|
-
|
|
154
|
+
|
|
151
155
|
}
|
|
152
156
|
}
|
|
153
|
-
}
|
|
157
|
+
}
|
|
154
158
|
})
|
|
155
|
-
|
|
159
|
+
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
|
-
|
|
162
|
+
|
|
159
163
|
}).catch(function (err) {
|
|
160
164
|
debugMessage(err);
|
|
161
165
|
});
|
|
@@ -172,15 +176,15 @@ module.exports = function(RED) {
|
|
|
172
176
|
|
|
173
177
|
async function getLocalToken(device) {
|
|
174
178
|
let data;
|
|
175
|
-
let options = {
|
|
179
|
+
let options = {
|
|
176
180
|
method: 'GET',
|
|
177
181
|
url: 'https://quasar.yandex.net/glagol/token',
|
|
178
182
|
qs: { device_id: device.id, platform: device.platform },
|
|
179
|
-
headers:
|
|
180
|
-
{
|
|
183
|
+
headers:
|
|
184
|
+
{
|
|
181
185
|
'Authorization': 'Oauth ' + node.token,
|
|
182
|
-
'Content-Type': 'application/json'
|
|
183
|
-
}
|
|
186
|
+
'Content-Type': 'application/json'
|
|
187
|
+
}
|
|
184
188
|
};
|
|
185
189
|
// debugMessage(JSON.stringify(options))
|
|
186
190
|
statusUpdate({"color": "yellow", "text": "connecting..."}, device);
|
|
@@ -188,7 +192,8 @@ module.exports = function(RED) {
|
|
|
188
192
|
.then(function(response)
|
|
189
193
|
{
|
|
190
194
|
data = JSON.parse(response);
|
|
191
|
-
device.token = data.token
|
|
195
|
+
device.token = data.token;
|
|
196
|
+
debugMessage(`${device.id}: Recieved conversation new token`)
|
|
192
197
|
})
|
|
193
198
|
.catch(function (err) {
|
|
194
199
|
removeDevice(node.readyList, device);
|
|
@@ -208,12 +213,12 @@ module.exports = function(RED) {
|
|
|
208
213
|
connect(device)
|
|
209
214
|
};
|
|
210
215
|
|
|
211
|
-
|
|
216
|
+
|
|
212
217
|
function connect(device) {
|
|
213
218
|
//connect only if !device.ws
|
|
214
219
|
//debugMessage(`device.ws = ${JSON.stringify(device.ws)}`);
|
|
215
220
|
if ( (device.connection == true || typeof(device.connection) == "undefined") && node.listenerCount(`statusUpdate_${device.id}`) > 0 ) {
|
|
216
|
-
debugMessage(`Connecting to device ${device.id}. ws is ${
|
|
221
|
+
debugMessage(`Connecting to device ${device.id}. ws is ${device.ws}. Listeners: ` + node.listenerCount(`statusUpdate_${device.id}`));
|
|
217
222
|
if (!device.ws) {
|
|
218
223
|
debugMessage('recieving conversation token...');
|
|
219
224
|
getLocalToken(device)
|
|
@@ -226,7 +231,7 @@ module.exports = function(RED) {
|
|
|
226
231
|
})
|
|
227
232
|
.catch(function (err) {
|
|
228
233
|
debugMessage('Error while getting token: ' + err);
|
|
229
|
-
|
|
234
|
+
|
|
230
235
|
});
|
|
231
236
|
} else {
|
|
232
237
|
if (device.ws.readyState == 3) {
|
|
@@ -258,16 +263,16 @@ module.exports = function(RED) {
|
|
|
258
263
|
//}
|
|
259
264
|
}
|
|
260
265
|
} else {
|
|
261
|
-
debugMessage(`${device.id} connection is disabled by settings in manager node ${device.manager} or you have not use any node for this station`)
|
|
262
|
-
statusUpdate({"color": "red", "text": "disconnected"}, device);
|
|
266
|
+
//debugMessage(`${device.id} connection is disabled by settings in manager node ${device.manager} or you have not use any node for this station`)
|
|
267
|
+
//statusUpdate({"color": "red", "text": "disconnected"}, device);
|
|
263
268
|
device.timer = setTimeout(connect, 60000, device);
|
|
264
269
|
|
|
265
270
|
}
|
|
266
271
|
|
|
267
272
|
}
|
|
268
|
-
|
|
273
|
+
|
|
269
274
|
async function makeConn(device) {
|
|
270
|
-
|
|
275
|
+
|
|
271
276
|
let options = {
|
|
272
277
|
key: device.glagol.security.server_private_key,
|
|
273
278
|
cert: device.glagol.security.server_certificate,
|
|
@@ -276,7 +281,9 @@ module.exports = function(RED) {
|
|
|
276
281
|
device.lastState = {};
|
|
277
282
|
debugMessage(`Connecting to wss://${device.address}:${device.port}`);
|
|
278
283
|
device.ws = new WebSocket(`wss://${device.address}:${device.port}`, options);
|
|
279
|
-
device.
|
|
284
|
+
debugMessage(`${device.id}: Fire connection watchdog for 60 seconds`);
|
|
285
|
+
device.watchDogConn = setTimeout(() => {reconnect(device)}, 60000);
|
|
286
|
+
device.ws.on('open', function open(data) {
|
|
280
287
|
debugMessage(`Connected to ${device.address}, data: ${data}`);
|
|
281
288
|
sendMessage(device.id, 'command', {payload: 'ping'});
|
|
282
289
|
statusUpdate({"color": "green", "text": "connected"}, device);
|
|
@@ -286,13 +293,15 @@ module.exports = function(RED) {
|
|
|
286
293
|
device.waitForIdle = false;
|
|
287
294
|
device.watchDog = setTimeout(() => device.ws.close(), 10000);
|
|
288
295
|
device.pingInterval = setInterval(onPing,300,device);
|
|
296
|
+
debugMessage(`${device.id}: Kill connection watchdog`);
|
|
297
|
+
clearTimeout(device.watchDogConn);
|
|
289
298
|
clearTimeout(device.timer);
|
|
290
|
-
debugMessage(`readyState: ${device.ws.readyState}`)
|
|
299
|
+
//debugMessage(`readyState: ${device.ws.readyState}`)
|
|
291
300
|
});
|
|
292
301
|
device.ws.on('message', function incoming(data) {
|
|
293
302
|
//debugMessage(`${device.id}: ${JSON.stringify(data)}`);
|
|
294
303
|
let dataRecieved = JSON.parse(data);
|
|
295
|
-
device.lastState = dataRecieved.state;
|
|
304
|
+
device.lastState = dataRecieved.state;
|
|
296
305
|
device.fullMessage = JSON.stringify(dataRecieved);
|
|
297
306
|
//debugMessage(checkSheduler(device, JSON.parse(data).sentTime));
|
|
298
307
|
node.emit(`message_${device.id}`, device.lastState);
|
|
@@ -312,7 +321,7 @@ module.exports = function(RED) {
|
|
|
312
321
|
if (device.lastState.playing && device.lastState.aliceState != 'LISTENING' && device.parameters.hasOwnProperty("sheduler")) {
|
|
313
322
|
let res = checkSheduler(device, dataRecieved.sentTime)
|
|
314
323
|
//debugMessage(`Result of cheking sheduler is ${res.toString}`);
|
|
315
|
-
if (!res[0]) {
|
|
324
|
+
if (!res[0]) {
|
|
316
325
|
if (device.shedulerFlag || device.shedulerFlag == undefined) {
|
|
317
326
|
node.emit('stopPlay', device, res[1])
|
|
318
327
|
device.shedulerFlag = false
|
|
@@ -324,7 +333,7 @@ module.exports = function(RED) {
|
|
|
324
333
|
clearTimeout(device.watchDog);
|
|
325
334
|
//debugMessage(`cleared timeout for ${device.id}`)
|
|
326
335
|
device.watchDog = setTimeout(() => {device.ws.close()}, 10000);
|
|
327
|
-
});
|
|
336
|
+
});
|
|
328
337
|
//device.ws.on('ping', function);
|
|
329
338
|
device.ws.on('close', function close(code, reason){
|
|
330
339
|
statusUpdate({"color": "red", "text": "disconnected"}, device);
|
|
@@ -336,15 +345,15 @@ module.exports = function(RED) {
|
|
|
336
345
|
debugMessage(`getting new token...`);
|
|
337
346
|
connect(device);
|
|
338
347
|
break;
|
|
339
|
-
case 1000:
|
|
348
|
+
case 1000:
|
|
340
349
|
debugMessage(`Closed connection code ${code} with reason ${reason}. Reconnecting...` );
|
|
341
350
|
connect(device);
|
|
342
|
-
break;
|
|
351
|
+
break;
|
|
343
352
|
case 1006:
|
|
344
353
|
debugMessage(`Lost server, reconnect in 60 seconds...${code} + ${reason}` );
|
|
345
354
|
device.timer = setTimeout(connect, 60000, device);
|
|
346
355
|
break;
|
|
347
|
-
|
|
356
|
+
|
|
348
357
|
case 10000:
|
|
349
358
|
debugMessage(`Reconnect device reason 10000 ${device.id}`);
|
|
350
359
|
connect(device);
|
|
@@ -356,15 +365,13 @@ module.exports = function(RED) {
|
|
|
356
365
|
}
|
|
357
366
|
|
|
358
367
|
|
|
359
|
-
})
|
|
368
|
+
})
|
|
360
369
|
device.ws.on('error', function error(data){
|
|
361
370
|
//statusUpdate({"color": "red", "text": "disconnected"}, device);
|
|
362
371
|
debugMessage(`error: ${data}`);
|
|
363
|
-
device.ws
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
// setTimeout(connect, 60000, device);
|
|
367
|
-
// }
|
|
372
|
+
if (typeof(device) !== 'undefined' && typeof(device.ws) !== 'undefined' ) {
|
|
373
|
+
device.ws.terminate();
|
|
374
|
+
}
|
|
368
375
|
});
|
|
369
376
|
};
|
|
370
377
|
|
|
@@ -417,7 +424,7 @@ module.exports = function(RED) {
|
|
|
417
424
|
return [{
|
|
418
425
|
"command": "rewind",
|
|
419
426
|
"position": 0
|
|
420
|
-
}]
|
|
427
|
+
}]
|
|
421
428
|
}
|
|
422
429
|
} else if (message.payload == 'volumeup') {
|
|
423
430
|
debugMessage(currentVolume);
|
|
@@ -425,7 +432,7 @@ module.exports = function(RED) {
|
|
|
425
432
|
return [{
|
|
426
433
|
"command": "setVolume",
|
|
427
434
|
"volume": currentVolume + 0.1
|
|
428
|
-
}]
|
|
435
|
+
}]
|
|
429
436
|
}
|
|
430
437
|
} else if (message.payload == 'volumedown') {
|
|
431
438
|
debugMessage(currentVolume);
|
|
@@ -433,13 +440,13 @@ module.exports = function(RED) {
|
|
|
433
440
|
return [{
|
|
434
441
|
"command": "setVolume",
|
|
435
442
|
"volume": currentVolume - 0.1
|
|
436
|
-
}]
|
|
443
|
+
}]
|
|
437
444
|
}
|
|
438
445
|
} else if (message.payload == 'volume') {
|
|
439
446
|
return [{
|
|
440
447
|
"command": "setVolume",
|
|
441
448
|
"volume": parseFloat(message.level)
|
|
442
|
-
}]
|
|
449
|
+
}]
|
|
443
450
|
}
|
|
444
451
|
|
|
445
452
|
} else {
|
|
@@ -447,7 +454,7 @@ module.exports = function(RED) {
|
|
|
447
454
|
//node.error(`You can send commands in msg.payload from list as String ${commands + extraCommands}`);
|
|
448
455
|
return [{"command": "ping"}];
|
|
449
456
|
}
|
|
450
|
-
case 'voice':
|
|
457
|
+
case 'voice':
|
|
451
458
|
debugMessage(`Message Voice command: ${message}`);
|
|
452
459
|
return [{
|
|
453
460
|
"command" : "sendText",
|
|
@@ -515,56 +522,84 @@ module.exports = function(RED) {
|
|
|
515
522
|
return result;
|
|
516
523
|
break;
|
|
517
524
|
case 'homekit':
|
|
518
|
-
debugMessage('HAP: ' + JSON.stringify(message) + ' PL: ' + JSON.stringify(message.payload) );
|
|
525
|
+
debugMessage('HAP: ' + JSON.stringify(message) + ' PL: ' + JSON.stringify(message.payload) );
|
|
519
526
|
if ("session" in message.hap) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
return messageConstructor('voice', {'payload': message.noTrackPhrase})
|
|
533
|
-
} else {
|
|
534
|
-
return messageConstructor('command', {'payload': 'ping'})
|
|
527
|
+
let playing = false;
|
|
528
|
+
let id = null;
|
|
529
|
+
let noTrackPhrase = message.noTrackPhrase;
|
|
530
|
+
|
|
531
|
+
if (typeof (device.lastState) !== 'undefined') {
|
|
532
|
+
let lastState = device.lastState;
|
|
533
|
+
if (typeof (lastState.playing) !== 'undefined') {
|
|
534
|
+
playing = lastState.playing;
|
|
535
|
+
}
|
|
536
|
+
if (typeof (lastState.playerState) !== 'undefined') {
|
|
537
|
+
if (typeof (lastState.playerState.id) !== 'undefined') {
|
|
538
|
+
id = lastState.playerState.id;
|
|
535
539
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
return messageConstructor('command', {'payload': '
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// speaker
|
|
544
|
+
if ("TargetMediaState" in message.payload) {
|
|
545
|
+
let TargetMediaState = message.payload.TargetMediaState;
|
|
546
|
+
if (id) {
|
|
547
|
+
return messageConstructor('command', { 'payload': (TargetMediaState ? 'stop' : 'play') })
|
|
548
|
+
} else if (!id && !TargetMediaState && noTrackPhrase) {
|
|
549
|
+
return messageConstructor('voice', { 'payload': noTrackPhrase })
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// tv
|
|
554
|
+
if ("Active" in message.payload) {
|
|
555
|
+
let Active = message.payload.Active;
|
|
556
|
+
if (id) {
|
|
557
|
+
return messageConstructor('command', { 'payload': (Active ? 'play' : 'stop') })
|
|
558
|
+
} else if (!id && Active && noTrackPhrase) {
|
|
559
|
+
return messageConstructor('voice', { 'payload': noTrackPhrase })
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// tv + RemoteKey
|
|
564
|
+
if ("RemoteKey" in message.payload) {
|
|
565
|
+
let RemoteKey = message.payload.RemoteKey;
|
|
566
|
+
switch (RemoteKey) {
|
|
567
|
+
case '7':
|
|
568
|
+
return messageConstructor('command', { 'payload': 'forward' }, device)
|
|
569
|
+
case '6':
|
|
570
|
+
return messageConstructor('command', { 'payload': 'backward' }, device)
|
|
571
|
+
case '4':
|
|
572
|
+
return messageConstructor('command', { 'payload': 'next' })
|
|
573
|
+
case '5':
|
|
574
|
+
return messageConstructor('command', { 'payload': 'prev' })
|
|
575
|
+
case '11':
|
|
576
|
+
if (playing) {
|
|
577
|
+
return messageConstructor('command', { 'payload': 'stop' })
|
|
548
578
|
} else {
|
|
549
|
-
|
|
579
|
+
if (id) {
|
|
580
|
+
return messageConstructor('command', { 'payload': 'play' })
|
|
581
|
+
} else if (!id && noTrackPhrase) {
|
|
582
|
+
return messageConstructor('voice', { 'payload': noTrackPhrase })
|
|
583
|
+
}
|
|
550
584
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
return messageConstructor('command', {'payload': 'ping'})
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// tv + VolumeSelector
|
|
589
|
+
if ("VolumeSelector" in message.payload) {
|
|
590
|
+
let VolumeSelector = message.payload.VolumeSelector;
|
|
591
|
+
return messageConstructor('command', { 'payload': (VolumeSelector ? 'volumedown' : 'volumeup') }, device)
|
|
559
592
|
}
|
|
560
|
-
|
|
593
|
+
|
|
594
|
+
debugMessage('unknown command')
|
|
595
|
+
return messageConstructor('command', { 'payload': 'ping' })
|
|
561
596
|
} else {
|
|
562
|
-
return messageConstructor('command', {'payload': 'ping'})
|
|
597
|
+
return messageConstructor('command', { 'payload': 'ping' })
|
|
563
598
|
}
|
|
564
|
-
case 'raw':
|
|
599
|
+
case 'raw':
|
|
565
600
|
if (Array.isArray(message.payload)) { return message.payload }
|
|
566
601
|
return [message.payload];
|
|
567
|
-
case 'stopListening':
|
|
602
|
+
case 'stopListening':
|
|
568
603
|
return [{
|
|
569
604
|
"command": "serverAction",
|
|
570
605
|
"serverActionEventPayload": {
|
|
@@ -576,7 +611,7 @@ module.exports = function(RED) {
|
|
|
576
611
|
|
|
577
612
|
}
|
|
578
613
|
function sendMessage(deviceId, messageType, message) {
|
|
579
|
-
|
|
614
|
+
|
|
580
615
|
try {
|
|
581
616
|
let device = searchDeviceByID(deviceId);
|
|
582
617
|
//debugMessage(`deviceId: ${searchDeviceByID(deviceId)}`);
|
|
@@ -617,19 +652,19 @@ module.exports = function(RED) {
|
|
|
617
652
|
//debugMessage(`timeCur: ${timeCurrent} timeMin: ${timeMin} timeMax: ${timeMax}`);
|
|
618
653
|
return [false, daySheduler.phrase];
|
|
619
654
|
}
|
|
620
|
-
|
|
655
|
+
|
|
621
656
|
|
|
622
657
|
}
|
|
623
|
-
|
|
658
|
+
|
|
624
659
|
function searchDeviceByID(id) {
|
|
625
660
|
if (node.deviceList) {
|
|
626
661
|
return node.deviceList.find(device => device.id == id)
|
|
627
|
-
}
|
|
662
|
+
}
|
|
628
663
|
}
|
|
629
664
|
function onPing(device) {
|
|
630
665
|
if (device) {sendMessage(device.id, 'command', {payload: 'ping'});}
|
|
631
666
|
}
|
|
632
|
-
|
|
667
|
+
|
|
633
668
|
function onPing(device) {
|
|
634
669
|
sendMessage(device.id, 'command', {payload: 'ping'});
|
|
635
670
|
}
|
|
@@ -638,19 +673,19 @@ module.exports = function(RED) {
|
|
|
638
673
|
if (device) {
|
|
639
674
|
if (device.ws) {
|
|
640
675
|
switch(device.ws.readyState){
|
|
641
|
-
case 0:
|
|
676
|
+
case 0:
|
|
642
677
|
return {"color": "yellow", "text": "connecting..."}
|
|
643
|
-
case 1:
|
|
678
|
+
case 1:
|
|
644
679
|
return {"color": "green", "text": "connected"}
|
|
645
|
-
case 2:
|
|
680
|
+
case 2:
|
|
646
681
|
return {"color": "red", "text": "disconnecting"}
|
|
647
|
-
case 3:
|
|
682
|
+
case 3:
|
|
648
683
|
return {"color": "red", "text": "disconnected"}
|
|
649
684
|
default:
|
|
650
685
|
return {"color": "red", "text": "disconnected"}
|
|
651
686
|
}
|
|
652
|
-
|
|
653
|
-
}
|
|
687
|
+
|
|
688
|
+
}
|
|
654
689
|
} else {
|
|
655
690
|
return {"color": "red", "text": "disconnected"}
|
|
656
691
|
}
|
|
@@ -658,7 +693,7 @@ module.exports = function(RED) {
|
|
|
658
693
|
}
|
|
659
694
|
|
|
660
695
|
|
|
661
|
-
|
|
696
|
+
|
|
662
697
|
function registerDevice(deviceId, nodeId, parameters) {
|
|
663
698
|
let device = searchDeviceByID(deviceId);
|
|
664
699
|
debugMessage(`Recieved parameters ${JSON.stringify(parameters)} for station id ${deviceId}`);
|
|
@@ -670,7 +705,7 @@ module.exports = function(RED) {
|
|
|
670
705
|
debugMessage(`Device ${device.id} already registered with manager id ${device.manager}. Updating parameters and restart...`);
|
|
671
706
|
reconnect(device);
|
|
672
707
|
return 1;
|
|
673
|
-
|
|
708
|
+
|
|
674
709
|
}
|
|
675
710
|
//новый и первый запрос на регистрацию для устройства
|
|
676
711
|
if (typeof(device.manager) == 'undefined') {
|
|
@@ -699,7 +734,7 @@ module.exports = function(RED) {
|
|
|
699
734
|
registrationBuffer.splice(registrationBuffer.indexOf(currentBuffer), 1)
|
|
700
735
|
debugMessage(`Element from registration buffer was deleted. Current buffer size is ${registrationBuffer.length}`)
|
|
701
736
|
}
|
|
702
|
-
reconnect(device);
|
|
737
|
+
reconnect(device);
|
|
703
738
|
return 0;
|
|
704
739
|
}
|
|
705
740
|
//новый запрос на регистрацию при наличии уже зарегистрированной ноды
|
|
@@ -717,9 +752,9 @@ module.exports = function(RED) {
|
|
|
717
752
|
registrationBuffer.push({"id": deviceId, "manager": nodeId, "parameters": parameters});
|
|
718
753
|
debugMessage(`New element in registration buffer. Current buffer size is ${registrationBuffer.length}`)
|
|
719
754
|
}
|
|
720
|
-
|
|
755
|
+
|
|
721
756
|
}
|
|
722
|
-
|
|
757
|
+
|
|
723
758
|
|
|
724
759
|
}
|
|
725
760
|
function unregisterDevice(deviceId, nodeId){
|
|
@@ -730,7 +765,7 @@ module.exports = function(RED) {
|
|
|
730
765
|
device.parameters = {};
|
|
731
766
|
debugMessage(`For device ${deviceId} was succesfully unregistred managment node whith id ${device.manager}`);
|
|
732
767
|
debugMessage(`device is: ${device}`);
|
|
733
|
-
return 0;
|
|
768
|
+
return 0;
|
|
734
769
|
} else {
|
|
735
770
|
return 2;
|
|
736
771
|
}
|
|
@@ -751,7 +786,7 @@ module.exports = function(RED) {
|
|
|
751
786
|
if (device.savedVolumeLevel) { sendMessage(device.id, 'raw',{payload: {
|
|
752
787
|
"command": "setVolume",
|
|
753
788
|
"volume": parseFloat(device.savedVolumeLevel)
|
|
754
|
-
}
|
|
789
|
+
}
|
|
755
790
|
});
|
|
756
791
|
}
|
|
757
792
|
device.waitForIdle = false;
|
|
@@ -760,13 +795,13 @@ module.exports = function(RED) {
|
|
|
760
795
|
function onStopPlay(device, phrase) {
|
|
761
796
|
sendMessage(device.id, 'command', {payload: 'stop'});
|
|
762
797
|
if (phrase.length > 0 && device.lastState.aliceState != 'SPEAKING') {sendMessage(device.id, 'tts', {payload: phrase, stopListening: true});}
|
|
763
|
-
}
|
|
798
|
+
}
|
|
764
799
|
function onClose() {
|
|
765
800
|
clearInterval(node.interval);
|
|
766
801
|
node.deviceList = [];
|
|
767
802
|
node.removeListener('deviceReady', onDeviceReady)
|
|
768
803
|
}
|
|
769
|
-
|
|
804
|
+
|
|
770
805
|
node.on('refreshHttp', function(activeList, readyList) {
|
|
771
806
|
RED.httpAdmin.get("/yandexdevices_"+node.id, RED.auth.needsPermission('yandex-login.read'), function(req,res) {
|
|
772
807
|
res.json({"devices": readyList});
|
|
@@ -775,8 +810,8 @@ module.exports = function(RED) {
|
|
|
775
810
|
res.json({"devices": activeList});
|
|
776
811
|
});
|
|
777
812
|
});
|
|
778
|
-
|
|
779
|
-
node.on('refreshHttpDNS', function(dnsList) {
|
|
813
|
+
|
|
814
|
+
node.on('refreshHttpDNS', function(dnsList) {
|
|
780
815
|
RED.httpAdmin.get("/mdns/"+node.id, RED.auth.needsPermission('yandex-login.read'), function(req,res) {
|
|
781
816
|
res.json({"SearchResult": dnsList});
|
|
782
817
|
});
|
|
@@ -800,7 +835,7 @@ module.exports = function(RED) {
|
|
|
800
835
|
res.json({"error": 'no device found'});
|
|
801
836
|
}
|
|
802
837
|
});
|
|
803
|
-
|
|
838
|
+
|
|
804
839
|
// main init
|
|
805
840
|
if (typeof(node.token) !== 'undefined') {
|
|
806
841
|
debugMessage(`Starting server with id ${node.id}`)
|