@evops/lightwaverf 0.0.7 → 0.0.8

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/dist/index.js CHANGED
@@ -1,40 +1,18 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
22
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
4
  };
24
5
  Object.defineProperty(exports, "__esModule", { value: true });
25
- const util_1 = __importDefault(require("util"));
26
- const events_1 = __importStar(require("events"));
27
- const dgram_1 = __importDefault(require("dgram"));
28
- const request_promise_1 = __importDefault(require("request-promise"));
6
+ const events_1 = require("events");
29
7
  const debug_1 = __importDefault(require("debug"));
30
- const debug = (0, debug_1.default)('lightwaverf');
8
+ const LightwaveRFClient_1 = require("./LightwaveRFClient");
9
+ const LightwaveAccount_1 = require("./LightwaveAccount");
31
10
  class LightwaveRFConfiguration {
32
11
  constructor() {
33
12
  this.timeout = 1000;
34
13
  }
35
14
  }
36
- /**
37
- * LightwaveRF API
15
+ /** * LightwaveRF API
38
16
  *
39
17
  * @param object config The config
40
18
  *
@@ -52,122 +30,117 @@ class LightwaveRF extends events_1.EventEmitter {
52
30
  this.messageCounter = 0;
53
31
  this.config = {};
54
32
  this.responseListeners = new Map();
55
- const self = this;
33
+ this.debug = (0, debug_1.default)('lightwaverf');
34
+ this.debug('Initialising LightwaveRF Client');
35
+ this.lwClient = new LightwaveRFClient_1.LightwaveRFClient(this.debug, config.ip);
36
+ this.lwClient.on('ready', () => {
37
+ this.debug('LightwaveRF ready');
38
+ this.initialiseConfiguration(callback);
39
+ });
56
40
  this.timeout = config.timeout || 1000;
57
41
  this.devices = []; //[{roomId:0,roomName:'',
58
42
  //deviceId:0,deviceName:'',
59
43
  //deviceType:''}];
60
- this.setMaxListeners(255);
61
- //Counter
62
- this.messageCounter = 0;
63
44
  //Config
64
45
  this.config = config;
65
- // Use broadcast to discover the IP
66
- this.config.ip = this.config.ip || '255.255.255.255';
67
- //Send Socket
68
- this.sendSocket = dgram_1.default.createSocket("udp4");
69
- //Receive socket
70
- this.receiveSocket = dgram_1.default.createSocket("udp4");
71
- //Receive message
72
- this.receiveSocket.on("message", function (message, rinfo) {
73
- // If we were using broadcast IP, we have now
74
- // discovered Link device IP and can switch off
75
- // broadcast
76
- if (self.config.ip == '255.255.255.255') {
77
- console.log("We have now discovered Link IP address: %s", rinfo.address);
78
- self.config.ip = rinfo.address;
79
- self.sendSocket.setBroadcast(false);
80
- }
81
- //Check this came from the lightwave unit
82
- if (rinfo.address !== self.config.ip) {
83
- //Came from wrong ip]
84
- console.warn("Response came from a different IP than our configured", rinfo.address, self.config.ip);
85
- return false;
86
- }
87
- const parseResponse = (buffer) => {
88
- const response = new Object();
89
- const message = buffer.toString('utf-8');
90
- if (message.match(/^\*!/)) {
91
- const jsonResponse = JSON.parse(message.replace(/^\*!/, ''));
92
- self.currentTransactionNumber = jsonResponse.trans + 1;
93
- Object.assign(response, jsonResponse);
94
- }
95
- else {
96
- //Split off the code for the message
97
- var parts = message.split(",");
98
- var trans = parts.splice(0, 1);
99
- var content = parts.join(",").replace(/(\r\n|\n|\r)/gm, "");
100
- response.trans = parseInt(trans[0]);
101
- response.message = content;
102
- }
103
- response.trans = response.trans !== null ? parseInt(response.trans) : null;
104
- response.error = response.pkt === "error" ? response.fn : null;
105
- return response;
106
- };
107
- let linkResponse = parseResponse(message);
108
- debug(">>>>>>>> Received response msg: %s, response: %s, rinfo: %s", message, linkResponse, rinfo);
109
- if (linkResponse.error === "nonRegistered" && !self.awaitRegistrration) {
110
- console.warn("Your device is not registered, please accept registration on the Link devices");
111
- self.register(() => { });
112
- }
113
- if (linkResponse.msg === "success" && linkResponse.pairType) {
114
- self.awaitRegistrration = false;
115
- }
116
- debug("Link response fn", linkResponse.fn);
117
- if (linkResponse.fn === "on") {
118
- self.emit("deviceTurnedOn", linkResponse.room, linkResponse.dev);
119
- }
120
- if (linkResponse.fn === "off") {
121
- self.emit("deviceTurnedOff", linkResponse.room, linkResponse.dev);
122
- }
123
- debug(self.responseListeners);
124
- var responseListenerData = self.responseListeners.get(linkResponse.trans);
125
- if (!responseListenerData) {
126
- debug("We haven't got anyone to respond to, ignoring the message");
127
- return;
128
- }
129
- responseListenerData.listener(linkResponse.error ? linkResponse.error : null, linkResponse.fn);
130
- self.responseListeners.delete(linkResponse.trans);
46
+ const self = this;
47
+ this.lwClient.on('deviceTurnedOn', function () {
48
+ self.emit('deviceTurnedOn', ...arguments);
131
49
  });
132
- this.receiveSocket.on("listening", function () {
133
- var address = self.receiveSocket.address();
134
- debug("Receiver socket listening " + address.address + ":" + address.port);
135
- self.send('@H', (code, err) => {
136
- if (err) {
137
- console.log('code', code, 'error', err);
138
- return;
139
- }
140
- self.initialiseConfiguration(callback);
141
- });
50
+ this.lwClient.on('deviceTurnedOff', function () {
51
+ self.emit('deviceTurnedOff', ...arguments);
142
52
  });
143
- this.sendSocket.bind();
144
- this.sendSocket.on('listening', () => {
145
- debug("Send socket is ready");
146
- debug("Setting up receiver socket");
147
- //Bind to the receive port
148
- self.receiveSocket.bind(9761);
53
+ this.lwClient.on('deviceDimmed', function () {
54
+ self.emit('deviceDimmed', ...arguments);
149
55
  });
56
+ //Receive message
57
+ // this.receiveSocket.on("message", function (message: Buffer, rinfo: dgram.RemoteInfo) {
58
+ // // If we were using broadcast IP, we have now
59
+ // // discovered Link device IP and can switch off
60
+ // // broadcast
61
+ // if (self.config.ip == '255.255.255.255') {
62
+ // console.log("We have now discovered Link IP address: %s", rinfo.address);
63
+ // self.config.ip = rinfo.address
64
+ // self.sendSocket.setBroadcast(false)
65
+ // }
66
+ // //Check this came from the lightwave unit
67
+ // if (rinfo.address !== self.config.ip) {
68
+ // //Came from wrong ip]
69
+ // console.warn("Response came from a different IP than our configured", rinfo.address, self.config.ip)
70
+ // return false;
71
+ // }
72
+ // const parseResponse = (buffer: Buffer) => {
73
+ // const response: any = new Object();
74
+ // const message = buffer.toString('utf-8');
75
+ // if (message.match(/^\*!/)) {
76
+ // const jsonResponse = JSON.parse(message.replace(/^\*!/, ''))
77
+ // self.currentTransactionNumber = jsonResponse.trans + 1;
78
+ // Object.assign(response, jsonResponse)
79
+ // response.error = response.pkt === "error" ? response.fn : null;
80
+ // } else {
81
+ // //Split off the code for the message
82
+ // var parts = message.split(",");
83
+ // var trans = parts.splice(0, 1);
84
+ // var content = parts.join(",").replace(/(\r\n|\n|\r)/gm, "");
85
+ // response.trans = parseInt(trans[0]);
86
+ // response.message = content;
87
+ // response.error = content.match("^ERR") ? content : null;
88
+ // }
89
+ // response.trans = response.trans !== null ? parseInt(response.trans) : null;
90
+ // return response;
91
+ // }
92
+ // let linkResponse = parseResponse(message)
93
+ // debug(">>>>>>>> Received response msg: %s, response: %s, rinfo: %s", message, linkResponse, rinfo);
94
+ // if (linkResponse.error === "nonRegistered" && !self.awaitRegistrration) {
95
+ // console.warn("Your device is not registered, please accept registration on the Link devices")
96
+ // self.register(() => { });
97
+ // }
98
+ // if (linkResponse.msg === "success" && linkResponse.pairType) {
99
+ // self.awaitRegistrration = false;
100
+ // }
101
+ // debug(self.responseListeners);
102
+ // var responseListenerData = self.responseListeners.get(linkResponse.trans);
103
+ // if (!responseListenerData) {
104
+ // debug("We haven't got anyone to respond to, ignoring the message")
105
+ // return;
106
+ // }
107
+ // debug(`[Transaction: ${linkResponse.trans}] Processing time: ${new Date().getTime() - responseListenerData.time}`)
108
+ // responseListenerData.listener(
109
+ // linkResponse.error,
110
+ // linkResponse.fn,
111
+ // );
112
+ // self.responseListeners.delete(linkResponse.trans);
113
+ // });
114
+ // this.receiveSocket.on("listening", function () {
115
+ // var address = self.receiveSocket.address();
116
+ // debug("Receiver socket listening " + address.address + ":" + address.port);
117
+ // self.send('@H', (code, err) => {
118
+ // if (err) {
119
+ // console.log('code', code, 'error', err)
120
+ // return
121
+ // }
122
+ // self.initialiseConfiguration(callback);
123
+ // })
124
+ // });
125
+ // this.sendSocket.bind();
126
+ // this.sendSocket.on('listening', () => {
127
+ // debug("Send socket is ready")
128
+ // debug("Setting up receiver socket")
129
+ // //Bind to the receive port
130
+ // self.receiveSocket.bind(9761);
131
+ // })
150
132
  process.on('SIGINT', () => {
151
- self.stop();
133
+ this.stop();
134
+ this.lwClient.stop();
152
135
  });
153
136
  }
154
137
  stop() {
155
- debug("Stopping server sockets");
156
- this.sendSocket.close();
157
- this.receiveSocket.close();
138
+ this.debug("Stopping server sockets");
158
139
  }
159
140
  initialiseConfiguration(callback) {
160
141
  //Check config
161
- if (!this.config.host) {
162
- this.config.host = "web.trustsmartcloud.com";
163
- }
164
- if (!this.config.email || !this.config.pin) {
165
- callback(null, "No email or pin specified. The server configuration (rooms, devices, etc.) cannot be obtained");
166
- this.stop();
167
- }
168
- else {
169
- this.getConfiguration(this.config.email, this.config.pin, this.config.host, callback);
170
- }
142
+ const lwAccount = new LightwaveAccount_1.LightwaveAccount(this.debug, this.lwClient, this.config.email, this.config.pin);
143
+ lwAccount.getConfiguration(callback);
171
144
  }
172
145
  /**
173
146
  * Register this device with the Wi-Fi Link
@@ -180,32 +153,6 @@ class LightwaveRF extends events_1.EventEmitter {
180
153
  this.awaitRegistrration = true;
181
154
  this.sendUdp("!F*p", callback);
182
155
  }
183
- /**
184
- * Request energy
185
- *
186
- * @param Function callback The callback function
187
- *
188
- * @return void
189
- */
190
- requestEnergy(callback) {
191
- this.sendUdp("@?\0", function (error, content) {
192
- if (error) {
193
- //Send error back
194
- callback(error);
195
- }
196
- else {
197
- //Determine if this is the energy monitor
198
- //ID,?W=current,max,today,yesterday (all kwh)
199
- var values = content.substring(3).split(",");
200
- callback(undefined, {
201
- current: parseInt(values[0], 10),
202
- max: parseInt(values[1], 10),
203
- today: parseInt(values[2], 10),
204
- yesterday: parseInt(values[3], 10)
205
- });
206
- }
207
- });
208
- }
209
156
  /**
210
157
  * Turn a device off
211
158
  *
@@ -229,58 +176,7 @@ class LightwaveRF extends events_1.EventEmitter {
229
176
  * @return void
230
177
  */
231
178
  turnDeviceOn(roomId, deviceId, callback) {
232
- var state = "1";
233
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
234
- }
235
- /**
236
- * Open a device
237
- *
238
- * @param integer roomId The room ID
239
- * @param integer deviceId The device ID
240
- * @param Function callback The callback for if there are any errors
241
- *
242
- * @return void
243
- */
244
- openDevice(roomId, deviceId, callback) {
245
- var state = ">";
246
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
247
- }
248
- /**
249
- * Close a device
250
- *
251
- * @param integer roomId The room ID
252
- * @param integer deviceId The device ID
253
- * @param Function callback The callback for if there are any errors
254
- *
255
- * @return void
256
- */
257
- closeDevice(roomId, deviceId, callback) {
258
- var state = "<";
259
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
260
- }
261
- /**
262
- * Stop a device
263
- *
264
- * @param integer roomId The room ID
265
- * @param integer deviceId The device ID
266
- * @param Function callback The callback for if there are any errors
267
- *
268
- * @return void
269
- */
270
- stopDevice(roomId, deviceId, callback) {
271
- var state = "^";
272
- this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
273
- }
274
- /**
275
- * Turn all devices in a room off
276
- *
277
- * @param integer roomId The room ID
278
- * @param Function callback The callback for if there are any errors
279
- *
280
- * @return void
281
- */
282
- turnRoomOff(roomId, callback) {
283
- this.exec("!R" + roomId + "Fa\0", callback);
179
+ // this.devices.find(d => d.roomId == roomId && d.deviceId == deviceId)?.turnOn();
284
180
  }
285
181
  /**
286
182
  * Set the dim percentage of a device
@@ -293,13 +189,12 @@ class LightwaveRF extends events_1.EventEmitter {
293
189
  * @return void
294
190
  */
295
191
  setDeviceDim(roomId, deviceId, dimPercentage, callback) {
296
- var dimAmount = dimPercentage * 0.32; //Dim is on a scale from 0 to 32
297
- if (dimAmount === 0) {
298
- this.turnDeviceOff(roomId, deviceId, callback);
299
- }
300
- else {
301
- this.exec("!R" + roomId + "D" + deviceId + "FdP" + dimAmount + "|\0", callback);
302
- }
192
+ // var dimAmount = dimPercentage * 0.32; //Dim is on a scale from 0 to 32
193
+ // if (dimAmount === 0) {
194
+ // this.turnDeviceOff(roomId, deviceId, callback);
195
+ // } else {
196
+ // this.exec("!R" + roomId + "D" + deviceId + "FdP" + dimAmount + "|\0", callback);
197
+ // }
303
198
  }
304
199
  /**
305
200
  * Get message code
@@ -314,7 +209,7 @@ class LightwaveRF extends events_1.EventEmitter {
314
209
  if (this.queue.length > 100) {
315
210
  this.queue.pop();
316
211
  }
317
- debug("Ading to queue: " + args.join(" "));
212
+ this.debug("Ading to queue: " + args.join(" "));
318
213
  this.queue.push(args);
319
214
  this.process();
320
215
  }
@@ -337,42 +232,41 @@ class LightwaveRF extends events_1.EventEmitter {
337
232
  const transactionNumber = this.getTransactionNumber();
338
233
  //Prepend code to message
339
234
  message = `${transactionNumber},${message}`;
340
- debug(`[${this.config.ip}][trans: ${transactionNumber}] Sending message: ${message}`);
235
+ this.debug(`[${this.config.ip}][trans: ${transactionNumber}] Sending message: ${message}`);
341
236
  //Create buffer from message
342
237
  const messageBuffer = Buffer.from(message, 'utf-8');
343
- this.sendSocket.setBroadcast(true);
344
- debug("Callback for message: " + message, callback);
238
+ this.debug("Callback for message: " + message, callback);
345
239
  //Add listener
346
240
  if (callback) {
347
- debug("Registering call back with transaction number: " + transactionNumber);
241
+ this.debug("Registering call back with transaction number: " + transactionNumber);
348
242
  this.responseListeners.set(transactionNumber, {
349
243
  time: new Date().getTime(),
350
244
  listener: callback
351
245
  });
352
- debug(this.responseListeners);
246
+ this.debug(this.responseListeners);
353
247
  // Expire request, trigger retry
354
248
  setTimeout(() => {
355
249
  const listener = this.responseListeners.get(transactionNumber);
356
250
  if (listener) {
357
- debug("The listener is still there, triggering error");
251
+ this.debug(`[Transaction $(transactionNumber)] The listener is still there, triggering error`);
358
252
  this.responseListeners.delete(transactionNumber);
359
253
  callback("ERR:EXPIRED", undefined);
360
254
  }
361
255
  }, 1000);
362
256
  }
363
257
  //Broadcast the message
364
- this.sendSocket.send(messageBuffer, 0, messageBuffer.length, 9760, this.config.ip);
258
+ // this.sendSocket.send(messageBuffer, 0, messageBuffer.length, 9760, this.config.ip);
365
259
  }
366
260
  process() {
367
- debug("Checking queue");
261
+ this.debug("Checking queue");
368
262
  if (this.queue.length === 0)
369
263
  return;
370
264
  if (!this.ready)
371
265
  return;
372
266
  var self = this;
373
267
  this.ready = false;
374
- debug("Processing queue...");
375
- debug("Items in the queue", this.queue.length);
268
+ this.debug("Processing queue...");
269
+ this.debug("Items in the queue", this.queue.length);
376
270
  this.send.apply(this, this.queue.shift());
377
271
  setTimeout(function () {
378
272
  self.ready = true;
@@ -380,126 +274,5 @@ class LightwaveRF extends events_1.EventEmitter {
380
274
  }, this.timeout);
381
275
  }
382
276
  ;
383
- /**
384
- * Parser to get de devices from https POST
385
- */
386
- getDevices(roomsString, devicesString, typesString, callback) {
387
- var nrRooms = 8;
388
- var nrDevicesPerRoom = 10;
389
- var tempRS = roomsString;
390
- var tempDS = devicesString;
391
- var tempTS = typesString;
392
- var deviceCounter = 0;
393
- for (var i = 0; i < nrRooms; i++) {
394
- var rId = i + 1;
395
- tempRS = tempRS.substring(tempRS.indexOf('\"') + 1);
396
- var rName = tempRS.substring(0, tempRS.indexOf('\"'));
397
- tempRS = tempRS.substring(tempRS.indexOf('\"') + 1);
398
- //console.log("room=" + rName);
399
- for (var j = 0; j < nrDevicesPerRoom; j++) {
400
- var dId = j + 1;
401
- tempDS = tempDS.substring(tempDS.indexOf('\"') + 1);
402
- var dName = tempDS.substring(0, tempDS.indexOf('\"'));
403
- tempDS = tempDS.substring(tempDS.indexOf('\"') + 1);
404
- //console.log("devices=" + dName);
405
- tempTS = tempTS.substring(tempTS.indexOf('\"') + 1);
406
- var dType = tempTS.substring(0, tempTS.indexOf('\"'));
407
- tempTS = tempTS.substring(tempTS.indexOf('\"') + 1);
408
- //console.log("devices=" + deviceName + " type=" + dType);
409
- // Get device types
410
- // O: On/Off Switch
411
- // D: Dimmer
412
- // R: Radiator(s)
413
- // P: Open/Close
414
- // I: Inactive (i.e. not configured)
415
- // m: Mood (inactive)
416
- // M: Mood (active)
417
- // o: All Off
418
- if (dType == "O" || dType == "D") {
419
- this.devices.push({
420
- roomId: rId, roomName: rName,
421
- deviceId: dId, deviceName: dName,
422
- deviceType: dType
423
- });
424
- //console.log("devices=" + deviceName + " type=" + deviceType);
425
- deviceCounter += 1;
426
- }
427
- }
428
- }
429
- if (callback)
430
- callback(this.devices, this);
431
- //console.log(this.devices);
432
- }
433
- parseRooms(lightwaveResponse, callback) {
434
- debug('Parsing lightwaveResponse: ', lightwaveResponse.content.estates[0].locations[0].zones[0].rooms[0].devices);
435
- var home = lightwaveResponse.content.estates[0].locations[0].zones[0];
436
- for (var i = 0; i < home.rooms.length; i++) {
437
- var r = home.rooms[i];
438
- debug("Room " + r.name + " with " + r.devices.length + " devices");
439
- // Get device types
440
- // O: On/Off Switch
441
- // D: Dimmer
442
- // R: Radiator(s)
443
- // P: Open/Close
444
- // I: Inactive (i.e. not configured)
445
- // m: Mood (inactive)
446
- // M: Mood (active)
447
- // o: All Off
448
- var deviceTypeMapping = {
449
- 1: 'L',
450
- 2: 'D',
451
- 3: 'P'
452
- };
453
- for (var j = 0; j < r.devices.length; j++) {
454
- var d = r.devices[j];
455
- const device = {
456
- roomId: r.room_number,
457
- roomName: r.name,
458
- deviceId: d.device_number,
459
- deviceName: d.name,
460
- deviceType: d.device_type_id
461
- };
462
- this.devices.push(device);
463
- }
464
- }
465
- debug('Devices:', this.devices);
466
- callback(this.devices, null);
467
- }
468
- ;
469
- /**
470
- * Connect to the server and obtain the configuration
471
- */
472
- getConfiguration(email, pin, manager_host, callback) {
473
- // An object of options to indicate where to post to
474
- debug('Getting rooms from LightWave');
475
- var self = this;
476
- var host = 'https://control-api.lightwaverf.com';
477
- var json = request_promise_1.default.defaults({
478
- json: true
479
- });
480
- var auth, token;
481
- json.get(host + '/v1/user?password=' + pin + '&username=' + email)
482
- .then(function (res) {
483
- return json.get(host + '/v1/auth?application_key=' + res.application_key);
484
- })
485
- .then(function (res) {
486
- token = res.token;
487
- auth = json.defaults({
488
- headers: {
489
- 'X-LWRF-token': token,
490
- 'X-LWRF-platform': 'ios',
491
- 'X-LWRF-skin': 'lightwaverf'
492
- }
493
- });
494
- return auth.get(host + '/v1/device_type?nested=1');
495
- })
496
- .then(function (res) {
497
- return auth.get(host + '/v1/user_profile?nested=1');
498
- })
499
- .then(function (res) {
500
- self.parseRooms(res, callback);
501
- });
502
- }
503
277
  }
504
- util_1.default.inherits(LightwaveRF, events_1.default.EventEmitter);
505
278
  exports.default = LightwaveRF;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@evops/lightwaverf",
3
3
  "description": "Lightwave RF client library",
4
- "version": "0.0.7",
4
+ "version": "0.0.8",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": "bin/lightwaverf.js",
@@ -25,7 +25,7 @@
25
25
  "@types/debug": "^4.1.7",
26
26
  "@types/js-yaml": "^4.0.5",
27
27
  "@types/request-promise": "^4.1.48",
28
- "debug": "~2.2.0",
28
+ "debug": "4.3.3",
29
29
  "js-yaml": ">=3.5.3",
30
30
  "request": "^2.74.0",
31
31
  "request-promise": "^4.1.1"