iobroker.fakeroku 0.2.0 → 0.2.2

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/main.js CHANGED
@@ -1,376 +1,376 @@
1
- /* jshint -W097 */// jshint strict:false
2
- /*jslint node: true */
3
- "use strict";
4
-
5
- var dgram = require('dgram');
6
- var http = require('http');
7
- var httpHeaders = require('http-headers');
8
-
9
- var utils = require(__dirname + '/lib/utils'); // Get common adapter utils
10
- var adapter = utils.adapter('fakeroku');
11
- var configChanged = false;
12
-
13
- var MULTICAST_IP;
14
- var BIND;
15
- var socket;
16
-
17
- var devices = {};
18
- var devArray = [];
19
-
20
- adapter.on('unload', function (callback) {
21
- try {
22
- adapter.log.info('cleaned everything up...');
23
- stopDiscovery();
24
- for (let j = 0; j < devArray.length; j++) {
25
- stopServer(devArray[j]);
26
- }
27
- callback();
28
- } catch (e) {
29
- callback();
30
- }
31
- });
32
-
33
- adapter.on('ready', function () {
34
- init();
35
- });
36
-
37
- function init() {
38
- MULTICAST_IP = adapter.config.MULTICAST_IP || "239.255.255.250";
39
- BIND = adapter.config.BIND || "0.0.0.0";
40
-
41
- for (var i = 0; i < adapter.config.devices.length; i++) {
42
- var dev = adapter.config.devices[i];
43
- var UUID = dev.uuid || genUUID(dev.name);
44
- var HTTP_PORT = Math.min(65535, Math.max(0, parseInt(dev.port, 10) || 9093));
45
- var SSDP_RESPONSE = new Buffer(
46
- "HTTP/1.1 200 OK\r\nCache-Control: max-age=300\r\nST: roku:ecp\r\nUSN: uuid:roku:ecp:" +
47
- UUID + "\r\nExt: \r\nServer: Roku UPnP/1.0 MiniUPnPd/1.4\r\nLOCATION: http://" +
48
- BIND + ":" + HTTP_PORT + "/\r\n\r\n"
49
- );
50
- var DESCXML = `<?xml version="1.0" encoding="UTF-8" ?>
51
- <root xmlns="urn:schemas-upnp-org:device-1-0">
52
- <specVersion>
53
- <major>1</major>
54
- <minor>0</minor>
55
- </specVersion>
56
- <device>
57
- <deviceType>urn:roku-com:device:player:1-0</deviceType>
58
- <friendlyName>${dev.name}</friendlyName>
59
- <manufacturer>Pmant</manufacturer>
60
- <manufacturerURL>https://github.com/Pmant/</manufacturerURL>
61
- <modelDescription>ioBroker fake Roku player</modelDescription>
62
- <modelName>${dev.name}</modelName>
63
- <modelNumber>4200X</modelNumber>
64
- <modelURL>https://github.com/Pmant/ioBroker.fakeroku</modelURL>
65
- <serialNumber>${UUID}</serialNumber>
66
- <UDN>uuid:roku:ecp:${UUID}</UDN>
67
- <serviceList>
68
- <service>
69
- <serviceType>urn:roku-com:service:ecp:1</serviceType>
70
- <serviceId>urn:roku-com:serviceId:ecp1-0</serviceId>
71
- <controlURL/>
72
- <eventSubURL/>
73
- <SCPDURL>ecp_SCPD.xml</SCPDURL>
74
- </service>
75
- </serviceList>
76
- </device>
77
- </root>`;
78
- var APPSXML = `<apps>
79
- <app id="11">Roku Channel Store</app>
80
- <app id="12">Netflix</app>
81
- <app id="13">Amazon Video on Demand</app>
82
- <app id="837">YouTube</app>
83
- <app id="2016">Crackle</app>
84
- <app id="3423">Rdio</app>
85
- <app id="21952">Blockbuster</app>
86
- <app id="31012">MGO</app>
87
- <app id="43594">CinemaNow</app>
88
- <app id="46041">Sling TV</app>
89
- <app id="50025">GooglePlay</app>
90
- </apps>`;
91
- devices[dev.name.replace(/[.\s]+/g, '_')] = {
92
- UUID: UUID,
93
- HTTP_PORT: HTTP_PORT,
94
- SSDP_RESPONSE: SSDP_RESPONSE,
95
- DESCXML: DESCXML,
96
- APPSXML: APPSXML,
97
- server: null,
98
- objects: [],
99
- sync: false
100
- };
101
- devArray.push(dev.name.replace(/[.\s]+/g, '_'));
102
- }
103
- //sync devices and channels
104
- adapter.getDevices(function (err, devs) {
105
- for (let d = 0; d < devs.length; d++) {
106
- //delete old device
107
- if (!devices[devs[d].common.name]) {
108
- adapter.deleteDevice(devs[d].common.name);
109
- adapter.log.debug('deleting old device ' + devs[d]._id);
110
- } else {
111
- devices[devs[d].common.name].sync = true;
112
- adapter.log.debug('found device ' + devs[d]._id);
113
- }
114
- }
115
-
116
- // create device and channels for new devices
117
- var devCreate = [];
118
- for (let j = 0; j < devArray.length; j++) {
119
- if (!devices[devArray[j]].sync) {
120
- devCreate.push(devArray[j]);
121
- }
122
- }
123
-
124
- if (devCreate.length) {
125
- for (let k = 0; k < devCreate.length; k++) {
126
- if (k === devCreate.length - 1) {
127
- createDevice(devCreate[k], true);
128
- } else {
129
- createDevice(devCreate[k], false);
130
- }
131
- }
132
- } else {
133
- if (configChanged) {
134
- updateConfig();
135
- }
136
- main();
137
- }
138
- });
139
- }
140
-
141
- function createDevice(device, last) {
142
- adapter.log.debug("creating device: " + device);
143
- adapter.createDevice(device, {name: device}, function () {
144
- adapter.log.debug("creating channels for " + device);
145
- adapter.createChannel(device, 'keys', {name: 'keys'}, function () {
146
- adapter.createChannel(device, 'apps', {name: 'apps'}, function () {
147
- devices[device].sync = true;
148
- if (last) main();
149
- });
150
- });
151
- });
152
- }
153
-
154
- function main() {
155
- for (let j = 0; j < devArray.length; j++) {
156
- startServer(devArray[j]);
157
- }
158
- startDiscovery();
159
- }
160
-
161
- function startServer(device, callback) {
162
- devices[device].server = http.createServer(function (request, response) {
163
- request.connection.ref();
164
- var method = request.method;
165
- var url = request.url;
166
- var body = [];
167
- request.on('error', function (err) {
168
- adapter.log.warn(err);
169
- }).on('data', function (chunk) {
170
- body.push(chunk);
171
- }).on('end', function () {
172
- response.on('error', function (err) {
173
- adapter.log.warn(err);
174
- });
175
- adapter.log.debug(method + "-request to " + url + " from " + request.connection.remoteAddress);
176
- if (method === 'GET' && url == '/') {
177
- response.statusCode = 200;
178
- response.setHeader('Content-Type', 'text/xml; charset=utf-8');
179
- response.setHeader('Connection', 'close');
180
- adapter.log.debug("sending service description");
181
- response.end(devices[device].DESCXML, function () {
182
- request.connection.unref();
183
- });
184
- } else {
185
- if (method === "GET") {
186
- var message = parseQuery(device, url);
187
- response.statusCode = 200;
188
- response.setHeader('Content-Type', 'text/xml; charset=utf-8');
189
- response.setHeader('Connection', 'close');
190
- adapter.log.debug("responding to get request");
191
- response.end(message, function () {
192
- request.connection.unref();
193
- });
194
- } else {
195
- parseCommand(device, url);
196
- response.end(function () {
197
- request.connection.unref();
198
- });
199
- }
200
- }
201
- });
202
- });
203
- devices[device].server.on('connection', function (socket) {
204
- socket.unref();
205
- });
206
- devices[device].server.on("error", function (err) {
207
- adapter.log.error(err);
208
- stopServer(device);
209
- });
210
- devices[device].server.listen(devices[device].HTTP_PORT, BIND, function () {
211
- adapter.log.debug("HTTP-Server started on " + BIND + ":" + devices[device].HTTP_PORT);
212
- });
213
- if (typeof callback === 'function') callback();
214
- }
215
-
216
- function stopServer(device) {
217
- if (devices[device].server) devices[device].server.close();
218
- }
219
-
220
- function startDiscovery() {
221
- socket = dgram.createSocket({type: 'udp4', reuseAddr: true});
222
- socket.on("error", function (error) {
223
- adapter.log.error(error);
224
- stopDiscovery();
225
- }
226
- );
227
- socket.on("message", function (msg, rinfo) {
228
- if (msg.toString().match(/^(M-SEARCH) \* HTTP\/1.\d/)) {
229
- var headers = httpHeaders(msg);
230
- if (headers.man === '"ssdp:discover"') {
231
- adapter.log.debug("responding to " + rinfo.address + ":" + rinfo.port);
232
- for (let j = 0; j < devArray.length; j++) {
233
- socket.send(devices[devArray[j]].SSDP_RESPONSE, 0, devices[devArray[j]].SSDP_RESPONSE.length, rinfo.port, rinfo.address);
234
- }
235
- }
236
- } else if (msg.toString().match(/^(NOTIFY) \* HTTP\/1.\d/)) {
237
- //@todo
238
- }
239
- }
240
- );
241
- socket.bind(1900, "0.0.0.0", function () {
242
- socket.addMembership(MULTICAST_IP);
243
- adapter.log.debug("listening on 0.0.0.0:1900");
244
- });
245
- }
246
-
247
- function stopDiscovery() {
248
- if (socket && socket._bindState) socket.close();
249
- }
250
-
251
- function parseCommand(device, command) {
252
- var m;
253
- if (m = command.match(/^\/([^\/]+)\/(\S+)$/)) {
254
- switch (m[1]) {
255
- case "keypress":
256
- //key is pressed once => set state to true for 50ms
257
- setState(device, "keys", m[2].replace(".", "_"), true, function (err) {
258
- if (err) return;
259
- setTimeout(function () {
260
- setState(device, "keys", m[2].replace(".", "_"), false);
261
- }, 50);
262
- });
263
- break;
264
- case "keydown":
265
- //key is pressed => set state to true
266
- setState(device, "keys", m[2].replace(".", "_"), true);
267
- break;
268
- case "keyup":
269
- //key is released => set state to false
270
- setState(device, "keys", m[2].replace(".", "_"), false);
271
- break;
272
- case "launch":
273
- //launch app => set state to true for 50ms
274
- setState(device, "apps", m[2].replace(".", "_"), true, function (err) {
275
- if (err) return;
276
- setTimeout(function () {
277
- setState(device, "apps", m[2].replace(".", "_"), false);
278
- }, 50);
279
- });
280
- break;
281
- case "install":
282
- //install app => set state to true for 50ms
283
- setState(device, "apps", m[2].replace(".", "_"), true, function (err) {
284
- if (err) return;
285
- setTimeout(function () {
286
- setState(device, "apps", m[2].replace(".", "_"), false);
287
- }, 50);
288
- });
289
- break;
290
- default:
291
- adapter.log.debug("unknown command: " + command);
292
- }
293
- } else {
294
- adapter.log.debug("unknown command: " + command);
295
- }
296
- }
297
-
298
- function parseQuery(device, query) {
299
- var message = "";
300
- switch (query) {
301
- case "/query/apps":
302
- message = devices[device].APPSXML;
303
- break;
304
- default:
305
- break;
306
- }
307
- return message;
308
- }
309
-
310
- function setState(device, channel, state, val, callback) {
311
- var id = device + "." + channel + "." + state;
312
- if (devices[device].objects[id]) {
313
- adapter.log.debug('state cached -> writing value');
314
- adapter.setState(id, {val: val, ack: true});
315
- if (typeof callback === 'function') callback();
316
- } else {
317
- adapter.getObject(id, function (err, obj) {
318
- if (err) {
319
- adapter.log.debug(err);
320
- if (typeof callback === 'function') callback(err);
321
- return;
322
- }
323
- if (!obj) {
324
- adapter.log.debug('creating new state');
325
- //create object first
326
- adapter.createState(device, channel, state, {
327
- name: state,
328
- def: false,
329
- type: 'boolean',
330
- read: 'true',
331
- write: 'false',
332
- role: 'indicator.state',
333
- }, {
334
- url: channel + "/" + state,
335
- }, function () {
336
- adapter.log.debug('created new state -> writing value');
337
- adapter.setState(id, {val: val, ack: true});
338
- devices[device].objects[id] = true;
339
- if (typeof callback === 'function') callback();
340
- });
341
- return;
342
- }
343
- adapter.log.debug('state found -> writing value');
344
- adapter.setState(id, {val: val, ack: true});
345
- devices[device].objects[id] = true;
346
- if (typeof callback === 'function') callback();
347
- });
348
- }
349
- }
350
-
351
- function genUUID(device) {
352
- var crypto = require('crypto');
353
- var uuid = crypto.createHash('md5').update(crypto.randomBytes(256)).digest("hex");
354
- for (var i = 0; i < adapter.config.devices.length; i++) {
355
- if (adapter.config.devices[i].name === device) {
356
- adapter.config.devices[i].uuid = uuid;
357
- }
358
- }
359
- configChanged = true;
360
- return uuid;
361
- }
362
-
363
- function updateConfig() {
364
- adapter.getForeignObject('system.adapter.fakeroku.' + adapter.instance, function (err, obj) {
365
- if (err || !obj) {
366
- adapter.log.warn("adapter config object not found!");
367
- return;
368
- }
369
- obj.native = adapter.config;
370
- adapter.log.debug("updating config with new uuid");
371
- adapter.setForeignObject('system.adapter.fakeroku.' + adapter.instance, obj, function () {
372
-
373
- });
374
- });
375
- }
376
-
1
+ /* jshint -W097 */// jshint strict:false
2
+ /*jslint node: true */
3
+ "use strict";
4
+
5
+ var dgram = require('dgram');
6
+ var http = require('http');
7
+ var httpHeaders = require('http-headers');
8
+
9
+ var utils = require('@iobroker/adapter-core'); // Get common adapter utils
10
+ var adapter = utils.Adapter('fakeroku');
11
+ var configChanged = false;
12
+
13
+ var MULTICAST_IP;
14
+ var BIND;
15
+ var socket;
16
+
17
+ var devices = {};
18
+ var devArray = [];
19
+
20
+ adapter.on('unload', function (callback) {
21
+ try {
22
+ adapter.log.info('cleaned everything up...');
23
+ stopDiscovery();
24
+ for (let j = 0; j < devArray.length; j++) {
25
+ stopServer(devArray[j]);
26
+ }
27
+ callback();
28
+ } catch (e) {
29
+ callback();
30
+ }
31
+ });
32
+
33
+ adapter.on('ready', function () {
34
+ init();
35
+ });
36
+
37
+ function init() {
38
+ MULTICAST_IP = adapter.config.MULTICAST_IP || "239.255.255.250";
39
+ BIND = adapter.config.BIND || "0.0.0.0";
40
+
41
+ for (var i = 0; i < adapter.config.devices.length; i++) {
42
+ var dev = adapter.config.devices[i];
43
+ var UUID = dev.uuid || genUUID(dev.name);
44
+ var HTTP_PORT = Math.min(65535, Math.max(0, parseInt(dev.port, 10) || 9093));
45
+ var SSDP_RESPONSE = new Buffer(
46
+ "HTTP/1.1 200 OK\r\nCache-Control: max-age=300\r\nST: roku:ecp\r\nUSN: uuid:roku:ecp:" +
47
+ UUID + "\r\nExt: \r\nServer: Roku UPnP/1.0 MiniUPnPd/1.4\r\nLOCATION: http://" +
48
+ BIND + ":" + HTTP_PORT + "/\r\n\r\n"
49
+ );
50
+ var DESCXML = `<?xml version="1.0" encoding="UTF-8" ?>
51
+ <root xmlns="urn:schemas-upnp-org:device-1-0">
52
+ <specVersion>
53
+ <major>1</major>
54
+ <minor>0</minor>
55
+ </specVersion>
56
+ <device>
57
+ <deviceType>urn:roku-com:device:player:1-0</deviceType>
58
+ <friendlyName>${dev.name}</friendlyName>
59
+ <manufacturer>Pmant</manufacturer>
60
+ <manufacturerURL>https://github.com/iobroker-community-adapters/</manufacturerURL>
61
+ <modelDescription>ioBroker fake Roku player</modelDescription>
62
+ <modelName>${dev.name}</modelName>
63
+ <modelNumber>4200X</modelNumber>
64
+ <modelURL>https://github.com/iobroker-community-adapters/ioBroker.fakeroku</modelURL>
65
+ <serialNumber>${UUID}</serialNumber>
66
+ <UDN>uuid:roku:ecp:${UUID}</UDN>
67
+ <serviceList>
68
+ <service>
69
+ <serviceType>urn:roku-com:service:ecp:1</serviceType>
70
+ <serviceId>urn:roku-com:serviceId:ecp1-0</serviceId>
71
+ <controlURL/>
72
+ <eventSubURL/>
73
+ <SCPDURL>ecp_SCPD.xml</SCPDURL>
74
+ </service>
75
+ </serviceList>
76
+ </device>
77
+ </root>`;
78
+ var APPSXML = `<apps>
79
+ <app id="11">Roku Channel Store</app>
80
+ <app id="12">Netflix</app>
81
+ <app id="13">Amazon Video on Demand</app>
82
+ <app id="837">YouTube</app>
83
+ <app id="2016">Crackle</app>
84
+ <app id="3423">Rdio</app>
85
+ <app id="21952">Blockbuster</app>
86
+ <app id="31012">MGO</app>
87
+ <app id="43594">CinemaNow</app>
88
+ <app id="46041">Sling TV</app>
89
+ <app id="50025">GooglePlay</app>
90
+ </apps>`;
91
+ devices[dev.name.replace(/[.\s]+/g, '_')] = {
92
+ UUID: UUID,
93
+ HTTP_PORT: HTTP_PORT,
94
+ SSDP_RESPONSE: SSDP_RESPONSE,
95
+ DESCXML: DESCXML,
96
+ APPSXML: APPSXML,
97
+ server: null,
98
+ objects: [],
99
+ sync: false
100
+ };
101
+ devArray.push(dev.name.replace(/[.\s]+/g, '_'));
102
+ }
103
+ //sync devices and channels
104
+ adapter.getDevices(function (err, devs) {
105
+ for (let d = 0; d < devs.length; d++) {
106
+ //delete old device
107
+ if (!devices[devs[d].common.name]) {
108
+ adapter.deleteDevice(devs[d].common.name);
109
+ adapter.log.debug('deleting old device ' + devs[d]._id);
110
+ } else {
111
+ devices[devs[d].common.name].sync = true;
112
+ adapter.log.debug('found device ' + devs[d]._id);
113
+ }
114
+ }
115
+
116
+ // create device and channels for new devices
117
+ var devCreate = [];
118
+ for (let j = 0; j < devArray.length; j++) {
119
+ if (!devices[devArray[j]].sync) {
120
+ devCreate.push(devArray[j]);
121
+ }
122
+ }
123
+
124
+ if (devCreate.length) {
125
+ for (let k = 0; k < devCreate.length; k++) {
126
+ if (k === devCreate.length - 1) {
127
+ createDevice(devCreate[k], true);
128
+ } else {
129
+ createDevice(devCreate[k], false);
130
+ }
131
+ }
132
+ } else {
133
+ if (configChanged) {
134
+ updateConfig();
135
+ }
136
+ main();
137
+ }
138
+ });
139
+ }
140
+
141
+ function createDevice(device, last) {
142
+ adapter.log.debug("creating device: " + device);
143
+ adapter.createDevice(device, {name: device}, function () {
144
+ adapter.log.debug("creating channels for " + device);
145
+ adapter.createChannel(device, 'keys', {name: 'keys'}, function () {
146
+ adapter.createChannel(device, 'apps', {name: 'apps'}, function () {
147
+ devices[device].sync = true;
148
+ if (last) main();
149
+ });
150
+ });
151
+ });
152
+ }
153
+
154
+ function main() {
155
+ for (let j = 0; j < devArray.length; j++) {
156
+ startServer(devArray[j]);
157
+ }
158
+ startDiscovery();
159
+ }
160
+
161
+ function startServer(device, callback) {
162
+ devices[device].server = http.createServer(function (request, response) {
163
+ request.connection.ref();
164
+ var method = request.method;
165
+ var url = request.url;
166
+ var body = [];
167
+ request.on('error', function (err) {
168
+ adapter.log.warn(err);
169
+ }).on('data', function (chunk) {
170
+ body.push(chunk);
171
+ }).on('end', function () {
172
+ response.on('error', function (err) {
173
+ adapter.log.warn(err);
174
+ });
175
+ adapter.log.debug(method + "-request to " + url + " from " + request.connection.remoteAddress);
176
+ if (method === 'GET' && url == '/') {
177
+ response.statusCode = 200;
178
+ response.setHeader('Content-Type', 'text/xml; charset=utf-8');
179
+ response.setHeader('Connection', 'close');
180
+ adapter.log.debug("sending service description");
181
+ response.end(devices[device].DESCXML, function () {
182
+ request.connection.unref();
183
+ });
184
+ } else {
185
+ if (method === "GET") {
186
+ var message = parseQuery(device, url);
187
+ response.statusCode = 200;
188
+ response.setHeader('Content-Type', 'text/xml; charset=utf-8');
189
+ response.setHeader('Connection', 'close');
190
+ adapter.log.debug("responding to get request");
191
+ response.end(message, function () {
192
+ request.connection.unref();
193
+ });
194
+ } else {
195
+ parseCommand(device, url);
196
+ response.end(function () {
197
+ request.connection.unref();
198
+ });
199
+ }
200
+ }
201
+ });
202
+ });
203
+ devices[device].server.on('connection', function (socket) {
204
+ socket.unref();
205
+ });
206
+ devices[device].server.on("error", function (err) {
207
+ adapter.log.error(err);
208
+ stopServer(device);
209
+ });
210
+ devices[device].server.listen(devices[device].HTTP_PORT, BIND, function () {
211
+ adapter.log.debug("HTTP-Server started on " + BIND + ":" + devices[device].HTTP_PORT);
212
+ });
213
+ if (typeof callback === 'function') callback();
214
+ }
215
+
216
+ function stopServer(device) {
217
+ if (devices[device].server) devices[device].server.close();
218
+ }
219
+
220
+ function startDiscovery() {
221
+ socket = dgram.createSocket({type: 'udp4', reuseAddr: true});
222
+ socket.on("error", function (error) {
223
+ adapter.log.error(error);
224
+ stopDiscovery();
225
+ }
226
+ );
227
+ socket.on("message", function (msg, rinfo) {
228
+ if (msg.toString().match(/^(M-SEARCH) \* HTTP\/1.\d/)) {
229
+ var headers = httpHeaders(msg);
230
+ if (headers.man === '"ssdp:discover"') {
231
+ adapter.log.debug("responding to " + rinfo.address + ":" + rinfo.port);
232
+ for (let j = 0; j < devArray.length; j++) {
233
+ socket.send(devices[devArray[j]].SSDP_RESPONSE, 0, devices[devArray[j]].SSDP_RESPONSE.length, rinfo.port, rinfo.address);
234
+ }
235
+ }
236
+ } else if (msg.toString().match(/^(NOTIFY) \* HTTP\/1.\d/)) {
237
+ //@todo
238
+ }
239
+ }
240
+ );
241
+ socket.bind(1900, "0.0.0.0", function () {
242
+ socket.addMembership(MULTICAST_IP);
243
+ adapter.log.debug("listening on 0.0.0.0:1900");
244
+ });
245
+ }
246
+
247
+ function stopDiscovery() {
248
+ if (socket && socket._bindState) socket.close();
249
+ }
250
+
251
+ function parseCommand(device, command) {
252
+ var m;
253
+ if (m = command.match(/^\/([^\/]+)\/(\S+)$/)) {
254
+ switch (m[1]) {
255
+ case "keypress":
256
+ //key is pressed once => set state to true for 50ms
257
+ setState(device, "keys", m[2].replace(".", "_"), true, function (err) {
258
+ if (err) return;
259
+ setTimeout(function () {
260
+ setState(device, "keys", m[2].replace(".", "_"), false);
261
+ }, 50);
262
+ });
263
+ break;
264
+ case "keydown":
265
+ //key is pressed => set state to true
266
+ setState(device, "keys", m[2].replace(".", "_"), true);
267
+ break;
268
+ case "keyup":
269
+ //key is released => set state to false
270
+ setState(device, "keys", m[2].replace(".", "_"), false);
271
+ break;
272
+ case "launch":
273
+ //launch app => set state to true for 50ms
274
+ setState(device, "apps", m[2].replace(".", "_"), true, function (err) {
275
+ if (err) return;
276
+ setTimeout(function () {
277
+ setState(device, "apps", m[2].replace(".", "_"), false);
278
+ }, 50);
279
+ });
280
+ break;
281
+ case "install":
282
+ //install app => set state to true for 50ms
283
+ setState(device, "apps", m[2].replace(".", "_"), true, function (err) {
284
+ if (err) return;
285
+ setTimeout(function () {
286
+ setState(device, "apps", m[2].replace(".", "_"), false);
287
+ }, 50);
288
+ });
289
+ break;
290
+ default:
291
+ adapter.log.debug("unknown command: " + command);
292
+ }
293
+ } else {
294
+ adapter.log.debug("unknown command: " + command);
295
+ }
296
+ }
297
+
298
+ function parseQuery(device, query) {
299
+ var message = "";
300
+ switch (query) {
301
+ case "/query/apps":
302
+ message = devices[device].APPSXML;
303
+ break;
304
+ default:
305
+ break;
306
+ }
307
+ return message;
308
+ }
309
+
310
+ function setState(device, channel, state, val, callback) {
311
+ var id = device + "." + channel + "." + state;
312
+ if (devices[device].objects[id]) {
313
+ adapter.log.debug('state cached -> writing value');
314
+ adapter.setState(id, {val: val, ack: true});
315
+ if (typeof callback === 'function') callback();
316
+ } else {
317
+ adapter.getObject(id, function (err, obj) {
318
+ if (err) {
319
+ adapter.log.debug(err);
320
+ if (typeof callback === 'function') callback(err);
321
+ return;
322
+ }
323
+ if (!obj) {
324
+ adapter.log.debug('creating new state');
325
+ //create object first
326
+ adapter.createState(device, channel, state, {
327
+ name: state,
328
+ def: false,
329
+ type: 'boolean',
330
+ read: 'true',
331
+ write: 'false',
332
+ role: 'indicator.state',
333
+ }, {
334
+ url: channel + "/" + state,
335
+ }, function () {
336
+ adapter.log.debug('created new state -> writing value');
337
+ adapter.setState(id, {val: val, ack: true});
338
+ devices[device].objects[id] = true;
339
+ if (typeof callback === 'function') callback();
340
+ });
341
+ return;
342
+ }
343
+ adapter.log.debug('state found -> writing value');
344
+ adapter.setState(id, {val: val, ack: true});
345
+ devices[device].objects[id] = true;
346
+ if (typeof callback === 'function') callback();
347
+ });
348
+ }
349
+ }
350
+
351
+ function genUUID(device) {
352
+ var crypto = require('crypto');
353
+ var uuid = crypto.createHash('md5').update(crypto.randomBytes(256)).digest("hex");
354
+ for (var i = 0; i < adapter.config.devices.length; i++) {
355
+ if (adapter.config.devices[i].name === device) {
356
+ adapter.config.devices[i].uuid = uuid;
357
+ }
358
+ }
359
+ configChanged = true;
360
+ return uuid;
361
+ }
362
+
363
+ function updateConfig() {
364
+ adapter.getForeignObject('system.adapter.fakeroku.' + adapter.instance, function (err, obj) {
365
+ if (err || !obj) {
366
+ adapter.log.warn("adapter config object not found!");
367
+ return;
368
+ }
369
+ obj.native = adapter.config;
370
+ adapter.log.debug("updating config with new uuid");
371
+ adapter.setForeignObject('system.adapter.fakeroku.' + adapter.instance, obj, function () {
372
+
373
+ });
374
+ });
375
+ }
376
+