@evops/lightwaverf 0.0.6 → 0.0.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/index.js DELETED
@@ -1,560 +0,0 @@
1
- var util = require('util');
2
- var events = require('events');
3
- var dgram = require('dgram');
4
- var https = require('https');
5
- var querystring = require('querystring');
6
- var fs = require('fs');
7
- var wait = require('wait.for');
8
- var yaml = require('js-yaml');
9
- var rp = require('request-promise');
10
- const { timeStamp } = require('console');
11
- var debug = require('debug')('lightwaverf');
12
-
13
- /**
14
- * LightwaveRF API
15
- *
16
- * @param object config The config
17
- *
18
- * An instance of the LightwaveRF API
19
- */
20
- function LightwaveRF(config, callback) {
21
- if (!(this instanceof LightwaveRF)) {
22
- return new LightwaveRF(config, callback);
23
- }
24
-
25
- const self = this;
26
- this.timeout = config.timeout || 1000;
27
- this.queue = [];
28
- this.ready = true;
29
-
30
- this.currentTransactionNumber = 0;
31
-
32
- this.devices = [];//[{roomId:0,roomName:'',
33
- //deviceId:0,deviceName:'',
34
- //deviceType:''}];
35
-
36
- events.EventEmitter.call(this);
37
-
38
- this.setMaxListeners(255);
39
-
40
- //Counter
41
- this.messageCounter = 0;
42
-
43
- //Config
44
- this.config = config;
45
-
46
- // Use broadcast to discover the IP
47
- this.config.ip = this.config.ip || '255.255.255.255';
48
-
49
- //Response listeners
50
- this.responseListeners = {};
51
-
52
- //Send Socket
53
- this.sendSocket = dgram.createSocket("udp4");
54
-
55
- //Receive socket
56
- this.receiveSocket = dgram.createSocket("udp4");
57
-
58
- //Receive message
59
- this.receiveSocket.on("message", function (message, rinfo) {
60
- // If we were using broadcast IP, we have now
61
- // discovered Link device IP and can switch off
62
- // broadcast
63
- if (this.config.ip == '255.255.255.255') {
64
- console.log("We have now discovered Link IP address: %s", rinfo.address);
65
- this.config.ip = rinfo.address
66
- this.sendSocket.setBroadcast(false)
67
- }
68
-
69
- //Check this came from the lightwave unit
70
- if (rinfo.address !== this.config.ip) {
71
- //Came from wrong ip]
72
- console.warn("Response came from a different IP than our configured", rinfo.address, this.config.ip)
73
- return false;
74
- }
75
-
76
- const parseResponse = (buffer) => {
77
- const response = {}
78
- const message = buffer.toString('utf-8');
79
- if (message.match(/^\*!/)) {
80
- const jsonResponse = JSON.parse(message.replace(/^\*!/, ''))
81
- self.currentTransactionNumber = jsonResponse.trans + 1;
82
-
83
- Object.assign(response, jsonResponse)
84
- } else {
85
- //Split off the code for the message
86
- var parts = message.split(",");
87
- var trans = parts.splice(0, 1);
88
- var content = parts.join(",").replace(/(\r\n|\n|\r)/gm, "");
89
- response.trans = parseInt(trans);
90
- response.message = content;
91
- }
92
-
93
- return response;
94
- }
95
-
96
- let linkResponse = parseResponse(message)
97
- debug(">>>>>>>> Received response msg: %s, rinfo: %s", message, linkResponse);
98
-
99
- var responseListenerData = this.responseListeners[linkResponse.trans];
100
- if (!responseListenerData) {
101
- debug("We haven't got anyone to respond to, ignoring the message")
102
- return;
103
- }
104
-
105
- responseListenerData.listener(
106
- linkResponse.error ? linkResponse.error : null,
107
- linkResponse.fn,
108
- );
109
-
110
- delete this.responseListeners[linkResponse.trans];
111
-
112
- }.bind(this));
113
-
114
- this.receiveSocket.on("listening", function () {
115
- var address = this.receiveSocket.address();
116
- debug("Receiver socket listening " + address.address + ":" + address.port);
117
-
118
- self.send('@H', (code, err) => {
119
- if (err) {
120
- console.log(code, err)
121
- }
122
-
123
- self.initialiseConfiguration(callback);
124
- })
125
- }.bind(this));
126
-
127
- this.sendSocket.bind();
128
- //Bind to the receive port
129
- this.receiveSocket.bind(9761);
130
-
131
- process.on('SIGINT', () => {
132
- self.stop();
133
- })
134
- }
135
- util.inherits(LightwaveRF, events.EventEmitter);
136
-
137
- LightwaveRF.prototype.stop = function () {
138
- debug("Stopping server sockets")
139
- this.sendSocket.close();
140
- this.receiveSocket.close();
141
- }
142
-
143
- LightwaveRF.prototype.initialiseConfiguration = function (callback) {
144
- if (this.config.file) {
145
- this.getFileConfiguration(this.config.file, callback);
146
- } else {
147
- debug("Not using `config.file`")
148
- //Check config
149
- if (!this.config.host) {
150
- this.config.host = "web.trustsmartcloud.com"
151
- }
152
-
153
- if (!this.config.email || !this.config.pin) {
154
- console.log("No email or pin specified. The server configuration (rooms, devices, etc.) cannot be obtained")
155
- }
156
- else {
157
- this.getConfiguration(this.config.email, this.config.pin, this.config.host, callback)
158
- }
159
- }
160
-
161
- }
162
-
163
- /**
164
- * Register this device with the Wi-Fi Link
165
- *
166
- * @param Function callback The callback function
167
- *
168
- * @return void
169
- */
170
- LightwaveRF.prototype.register = function (callback) {
171
- this.sendUdp("!R1Fa", callback);
172
- }
173
-
174
- /**
175
- * Request energy
176
- *
177
- * @param Function callback The callback function
178
- *
179
- * @return void
180
- */
181
- LightwaveRF.prototype.requestEnergy = function (callback) {
182
- this.sendUdp("@?\0", function (error, content) {
183
- if (error) {
184
- //Send error back
185
- callback(error);
186
- } else {
187
- //Determine if this is the energy monitor
188
- //ID,?W=current,max,today,yesterday (all kwh)
189
- var values = content.substring(3).split(",");
190
- callback(undefined, {
191
- current: parseInt(values[0], 10),
192
- max: parseInt(values[1], 10),
193
- today: parseInt(values[2], 10),
194
- yesterday: parseInt(values[3], 10)
195
- });
196
- }
197
- });
198
- }
199
-
200
- /**
201
- * Turn a device off
202
- *
203
- * @param integer roomId The room ID
204
- * @param integer deviceId The device ID
205
- * @param Function callback The callback for if there are any errors
206
- *
207
- * @return void
208
- */
209
- LightwaveRF.prototype.turnDeviceOff = function (roomId, deviceId, callback) {
210
- var state = "0";
211
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
212
- }
213
-
214
- /**
215
- * Turn a device on
216
- *
217
- * @param integer roomId The room ID
218
- * @param integer deviceId The device ID
219
- * @param Function callback The callback for if there are any errors
220
- *
221
- * @return void
222
- */
223
- LightwaveRF.prototype.turnDeviceOn = function (roomId, deviceId, callback) {
224
- var state = "1";
225
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
226
- }
227
-
228
- /**
229
- * Open a device
230
- *
231
- * @param integer roomId The room ID
232
- * @param integer deviceId The device ID
233
- * @param Function callback The callback for if there are any errors
234
- *
235
- * @return void
236
- */
237
- LightwaveRF.prototype.openDevice = function (roomId, deviceId, callback) {
238
- var state = ">";
239
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
240
- }
241
-
242
- /**
243
- * Close a device
244
- *
245
- * @param integer roomId The room ID
246
- * @param integer deviceId The device ID
247
- * @param Function callback The callback for if there are any errors
248
- *
249
- * @return void
250
- */
251
- LightwaveRF.prototype.closeDevice = function (roomId, deviceId, callback) {
252
- var state = "<";
253
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
254
- }
255
-
256
- /**
257
- * Stop a device
258
- *
259
- * @param integer roomId The room ID
260
- * @param integer deviceId The device ID
261
- * @param Function callback The callback for if there are any errors
262
- *
263
- * @return void
264
- */
265
- LightwaveRF.prototype.stopDevice = function (roomId, deviceId, callback) {
266
- var state = "^";
267
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
268
- }
269
-
270
- /**
271
- * Turn all devices in a room off
272
- *
273
- * @param integer roomId The room ID
274
- * @param Function callback The callback for if there are any errors
275
- *
276
- * @return void
277
- */
278
- LightwaveRF.prototype.turnRoomOff = function (roomId, callback) {
279
- this.exec("!R" + roomId + "Fa\0", callback);
280
- }
281
-
282
- /**
283
- * Set the dim percentage of a device
284
- *
285
- * @param integer roomId The room ID
286
- * @param integer deviceId The device ID
287
- * @param integer dimPercentage The percentage to set the device dim
288
- * @param Function callback The callback for if there are any errors
289
- *
290
- * @return void
291
- */
292
- LightwaveRF.prototype.setDeviceDim = function (roomId, deviceId, dimPercentage, callback) {
293
- var dimAmount = parseInt(dimPercentage * 0.32, 10); //Dim is on a scale from 0 to 32
294
-
295
- if (dimAmount === 0) {
296
- this.turnDeviceOff(roomId, deviceId, callback);
297
- } else {
298
- this.exec("!R" + roomId + "D" + deviceId + "FdP" + dimAmount + "|\0", callback);
299
- }
300
- }
301
-
302
- /**
303
- * Get message code
304
- *
305
- * @return string
306
- */
307
- LightwaveRF.prototype.getTransactionNumber = function () {
308
- return this.currentTransactionNumber;
309
- }
310
-
311
-
312
- LightwaveRF.prototype.exec = function () {
313
- // Check if the queue has a reasonable size
314
- if (this.queue.length > 100) {
315
- this.queue.pop();
316
- }
317
-
318
- this.queue.push(arguments);
319
- this.process();
320
- };
321
-
322
- LightwaveRF.prototype.send = function (cmd, callback) {
323
- this.sendUdp(cmd, callback);
324
- //if (callback) callback();
325
- };
326
- /**
327
- * Send a message over udp
328
- *
329
- * @param string message The message to send
330
- * @param Function callback The callback for if there are any errors
331
- *
332
- * @return void
333
- */
334
- LightwaveRF.prototype.sendUdp = function (message, callback) {
335
- //Add to message
336
- const transactionNumber = this.getTransactionNumber();
337
-
338
- //Prepend code to message
339
- message = transactionNumber + "," + message;
340
-
341
- debug(`[${this.config.ip}] Sending message: ${message}`);
342
-
343
- //Create buffer from message
344
- const messageBuffer = Buffer.from(message, 'utf-8');
345
-
346
- this.sendSocket.setBroadcast(true);
347
-
348
- //Broadcast the message
349
- this.sendSocket.send(messageBuffer, 0, messageBuffer.length, 9760, this.config.ip);
350
-
351
- //Add listener
352
- if (callback) {
353
- this.responseListeners[transactionNumber] = {
354
- time: new Date().getTime(),
355
- listener: callback
356
- };
357
-
358
- // Expire request, trigger retry
359
- setTimeout(() => {
360
- const listener = this.responseListeners[transactionNumber];
361
- if (listener) {
362
- debug("The listener is still there, triggering error");
363
- delete this.responseListeners[transactionNumber];
364
- callback("ERR:EXPIRED", undefined);
365
- }
366
- }, 1000);
367
- }
368
- }
369
-
370
- LightwaveRF.prototype.process = function () {
371
- if (this.queue.length === 0) return;
372
- if (!this.ready) return;
373
- var self = this;
374
- this.ready = false;
375
- this.send.apply(this, this.queue.shift());
376
- setTimeout(function () {
377
- self.ready = true;
378
- self.process();
379
- }, this.timeout);
380
- };
381
-
382
-
383
- /**
384
- * Parser to get de devices from https POST
385
- */
386
- LightwaveRF.prototype.getDevices = function (roomsString, devicesString, typesString, callback) {
387
-
388
- var nrRooms = 8;
389
- var nrDevicesPerRoom = 10;
390
-
391
- var tempRS = roomsString;
392
- var tempDS = devicesString;
393
- var tempTS = typesString;
394
- var deviceCounter = 0;
395
- for (var i = 0; i < nrRooms; i++) {
396
- var rId = i + 1;
397
-
398
- tempRS = tempRS.substring(tempRS.indexOf('\"') + 1);
399
- var rName = tempRS.substring(0, tempRS.indexOf('\"'));
400
- tempRS = tempRS.substring(tempRS.indexOf('\"') + 1);
401
- //console.log("room=" + rName);
402
-
403
- for (var j = 0; j < nrDevicesPerRoom; j++) {
404
- var dId = j + 1;
405
-
406
- tempDS = tempDS.substring(tempDS.indexOf('\"') + 1);
407
- var dName = tempDS.substring(0, tempDS.indexOf('\"'));
408
- tempDS = tempDS.substring(tempDS.indexOf('\"') + 1);
409
- //console.log("devices=" + dName);
410
-
411
- tempTS = tempTS.substring(tempTS.indexOf('\"') + 1);
412
- var dType = tempTS.substring(0, tempTS.indexOf('\"'));
413
- tempTS = tempTS.substring(tempTS.indexOf('\"') + 1);
414
- //console.log("devices=" + deviceName + " type=" + dType);
415
-
416
- // Get device types
417
- // O: On/Off Switch
418
- // D: Dimmer
419
- // R: Radiator(s)
420
- // P: Open/Close
421
- // I: Inactive (i.e. not configured)
422
- // m: Mood (inactive)
423
- // M: Mood (active)
424
- // o: All Off
425
- if (dType == "O" || dType == "D") {
426
- this.devices.push({
427
- roomId: rId, roomName: rName,
428
- deviceId: dId, deviceName: dName,
429
- deviceType: dType
430
- });
431
- //console.log("devices=" + deviceName + " type=" + deviceType);
432
- deviceCounter += 1;
433
- }
434
- }
435
- }
436
-
437
- if (callback) callback(this.devices, this);
438
-
439
- //console.log(this.devices);
440
- }
441
-
442
- /**
443
- * Read configuration from a lightwaverf Gem YAML file
444
- */
445
- LightwaveRF.prototype.getFileConfiguration = function (file, callback) {
446
- try {
447
- var that = this,
448
- yamlConfig = yaml.safeLoad(fs.readFileSync(file, 'utf8'));
449
-
450
- yamlConfig['room'].forEach(function (room, roomIndex) {
451
- room['device'].
452
- filter(function (device) {
453
- return device['type'] == 'O' || device['type'] == 'D';
454
- }).
455
- forEach(function (device, deviceIndex) {
456
- that.devices.push({
457
- roomId: room['id'] ? parseInt(room['id'].substring(1)) : roomIndex + 1,
458
- roomName: room['name'],
459
- deviceId: device['id'] ? parseInt(device['id'].substring(1)) : deviceIndex + 1,
460
- deviceName: device['name'],
461
- deviceType: device['type']
462
- });
463
- });
464
- });
465
-
466
- if (callback) {
467
- callback(that.devices, that);
468
- }
469
-
470
- //console.log(that.devices);
471
-
472
- } catch (e) {
473
- console.log('Unable to read YAML file ' + file);
474
- console.log(e);
475
- }
476
- };
477
-
478
- LightwaveRF.prototype.parseRooms = function (lightwaveResponse, callback) {
479
- debug('Parsing lightwaveResponse: ',
480
- lightwaveResponse.content.estates[0].locations[0].zones[0].rooms[0].devices);
481
-
482
- var home = lightwaveResponse.content.estates[0].locations[0].zones[0];
483
-
484
- for (var i = 0; i < home.rooms.length; i++) {
485
- var r = home.rooms[i];
486
-
487
- debug("Room " + r.name + " with " + r.devices.length + " devices");
488
-
489
- // Get device types
490
- // O: On/Off Switch
491
- // D: Dimmer
492
- // R: Radiator(s)
493
- // P: Open/Close
494
- // I: Inactive (i.e. not configured)
495
- // m: Mood (inactive)
496
- // M: Mood (active)
497
- // o: All Off
498
- var deviceTypeMapping = {
499
- 1: 'L',
500
- 2: 'D',
501
- 3: 'P'
502
- }
503
-
504
- for (var j = 0; j < r.devices.length; j++) {
505
- var d = r.devices[j];
506
-
507
- this.devices.push({
508
- roomId: r.room_number,
509
- roomName: r.name,
510
- deviceId: d.device_number,
511
- deviceName: d.name,
512
- deviceType: deviceTypeMapping[d.device_type_id]
513
- });
514
- }
515
- }
516
-
517
- debug('Devices:', this.devices)
518
-
519
- callback(this.devices, this);
520
- };
521
-
522
- /**
523
- * Connect to the server and obtain the configuration
524
- */
525
- LightwaveRF.prototype.getConfiguration = function (email, pin, manager_host, callback) {
526
- // An object of options to indicate where to post to
527
-
528
- debug('Getting rooms from LightWave');
529
- var self = this;
530
- var host = 'https://control-api.lightwaverf.com';
531
- var json = rp.defaults({
532
- json: true
533
- });
534
- var auth, token;
535
- json.get(host + '/v1/user?password=' + pin + '&username=' + email)
536
- .then(function (res) {
537
- return json.get(host + '/v1/auth?application_key=' + res.application_key)
538
- })
539
- .then(function (res) {
540
- token = res.token;
541
- auth = json.defaults({
542
- headers: {
543
- 'X-LWRF-token': token,
544
- 'X-LWRF-platform': 'ios',
545
- 'X-LWRF-skin': 'lightwaverf'
546
- }
547
- });
548
-
549
- return auth.get(host + '/v1/device_type?nested=1');
550
- })
551
- .then(function (res) {
552
- debug(res);
553
- return auth.get(host + '/v1/user_profile?nested=1')
554
- })
555
- .then(function (res) {
556
- self.parseRooms(res, callback);
557
- });
558
- }
559
-
560
- module.exports = LightwaveRF;
package/test.js DELETED
@@ -1,19 +0,0 @@
1
- console.log("Testing rapid turning on and off");
2
-
3
- const LightwaveRF = require('./');
4
- const lw = new LightwaveRF({
5
- 'email': 'stan@wozniak.com',
6
- 'pin': 2212,
7
- 'timeout': 750
8
- }, devices => {
9
- const ROOM = 1;
10
- const DEVICES = [1];
11
-
12
- DEVICES.forEach(d => {
13
- lw.turnDeviceOn(ROOM, d);
14
- setTimeout(lw.turnDeviceOff.bind(lw, ROOM, d, () => {
15
- console.log("We are done");
16
- lw.stop();
17
- }), 300);
18
- });
19
- })