@evops/lightwaverf 0.0.4 → 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/LICENSE +7 -0
- package/README.md +2 -82
- package/dist/LightwaveAccount.d.ts +13 -0
- package/dist/LightwaveAccount.js +81 -0
- package/dist/LightwaveDevice.d.ts +26 -0
- package/dist/LightwaveDevice.js +64 -0
- package/dist/LightwaveJsonMessageProcessor.d.ts +10 -0
- package/dist/LightwaveJsonMessageProcessor.js +24 -0
- package/dist/LightwaveMessage.d.ts +9 -0
- package/dist/LightwaveMessage.js +2 -0
- package/dist/LightwaveMessageProcessor.d.ts +7 -0
- package/dist/LightwaveMessageProcessor.js +3 -0
- package/dist/LightwaveRFClient.d.ts +32 -0
- package/dist/LightwaveRFClient.js +202 -0
- package/dist/LightwaveTextMessageProcessor.d.ts +10 -0
- package/dist/LightwaveTextMessageProcessor.js +25 -0
- package/dist/LightwaveTransaction.d.ts +8 -0
- package/dist/LightwaveTransaction.js +2 -0
- package/dist/Queue.d.ts +7 -0
- package/dist/Queue.js +19 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.js +278 -0
- package/package.json +15 -11
- package/src/LightwaveAccount.ts +107 -0
- package/src/LightwaveDevice.ts +66 -0
- package/src/LightwaveJsonMessageProcessor.ts +29 -0
- package/src/LightwaveMessageProcessor.ts +8 -0
- package/src/LightwaveRFClient.ts +236 -0
- package/src/LightwaveTextMessageProcessor.ts +30 -0
- package/src/LightwaveTransaction.ts +9 -0
- package/src/Queue.ts +17 -0
- package/src/index.ts +332 -0
- package/bin/lightwaverf.js +0 -27
- package/index.js +0 -551
- package/test.js +0 -17
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import Debug from 'debug';
|
|
4
|
+
import { LightwaveRFClient } from './LightwaveRFClient';
|
|
5
|
+
import { LightwaveDevice } from './LightwaveDevice';
|
|
6
|
+
declare class LightwaveRFConfiguration {
|
|
7
|
+
timeout?: number;
|
|
8
|
+
ip?: string;
|
|
9
|
+
file?: any;
|
|
10
|
+
host?: any;
|
|
11
|
+
email?: any;
|
|
12
|
+
pin?: any;
|
|
13
|
+
}
|
|
14
|
+
declare interface ILightwaveRF {
|
|
15
|
+
on(event: 'deviceTurnedOn', listener: (roomId: number, deviceId: number) => void): this;
|
|
16
|
+
on(event: 'deviceTurnedOff', listener: (roomId: number, deviceId: number) => void): this;
|
|
17
|
+
on(event: 'deviceDimmed', listener: (roomId: number, deviceId: number, percentage: number) => void): this;
|
|
18
|
+
}
|
|
19
|
+
/** * LightwaveRF API
|
|
20
|
+
*
|
|
21
|
+
* @param object config The config
|
|
22
|
+
*
|
|
23
|
+
* An instance of the LightwaveRF API
|
|
24
|
+
*/
|
|
25
|
+
export default class LightwaveRF extends EventEmitter implements ILightwaveRF {
|
|
26
|
+
timeout: number;
|
|
27
|
+
queue: any;
|
|
28
|
+
ready: boolean;
|
|
29
|
+
awaitRegistrration: boolean;
|
|
30
|
+
currentTransactionNumber: number;
|
|
31
|
+
devices: Array<LightwaveDevice>;
|
|
32
|
+
messageCounter: number;
|
|
33
|
+
config: LightwaveRFConfiguration;
|
|
34
|
+
responseListeners: Map<number, any>;
|
|
35
|
+
lwClient: LightwaveRFClient;
|
|
36
|
+
debug: Debug.Debugger;
|
|
37
|
+
constructor(config: LightwaveRFConfiguration, callback: (config: any, error: any) => void);
|
|
38
|
+
stop(): void;
|
|
39
|
+
initialiseConfiguration(callback: (config: any, error: string) => void): void;
|
|
40
|
+
/**
|
|
41
|
+
* Register this device with the Wi-Fi Link
|
|
42
|
+
*
|
|
43
|
+
* @param Function callback The callback function
|
|
44
|
+
*
|
|
45
|
+
* @return void
|
|
46
|
+
*/
|
|
47
|
+
register(callback: any): void;
|
|
48
|
+
/**
|
|
49
|
+
* Turn a device off
|
|
50
|
+
*
|
|
51
|
+
* @param integer roomId The room ID
|
|
52
|
+
* @param integer deviceId The device ID
|
|
53
|
+
* @param Function callback The callback for if there are any errors
|
|
54
|
+
*
|
|
55
|
+
* @return void
|
|
56
|
+
*/
|
|
57
|
+
turnDeviceOff(roomId: number, deviceId: number, callback?: any): void;
|
|
58
|
+
/**
|
|
59
|
+
* Turn a device on
|
|
60
|
+
*
|
|
61
|
+
* @param integer roomId The room ID
|
|
62
|
+
* @param integer deviceId The device ID
|
|
63
|
+
* @param Function callback The callback for if there are any errors
|
|
64
|
+
*
|
|
65
|
+
* @return void
|
|
66
|
+
*/
|
|
67
|
+
turnDeviceOn(roomId: number, deviceId: number, callback?: any): void;
|
|
68
|
+
/**
|
|
69
|
+
* Set the dim percentage of a device
|
|
70
|
+
*
|
|
71
|
+
* @param integer roomId The room ID
|
|
72
|
+
* @param integer deviceId The device ID
|
|
73
|
+
* @param integer dimPercentage The percentage to set the device dim
|
|
74
|
+
* @param Function callback The callback for if there are any errors
|
|
75
|
+
*
|
|
76
|
+
* @return void
|
|
77
|
+
*/
|
|
78
|
+
setDeviceDim(roomId: string, deviceId: string, dimPercentage: number, callback: any): void;
|
|
79
|
+
/**
|
|
80
|
+
* Get message code
|
|
81
|
+
*
|
|
82
|
+
* @return string
|
|
83
|
+
*/
|
|
84
|
+
private getTransactionNumber;
|
|
85
|
+
private exec;
|
|
86
|
+
private send;
|
|
87
|
+
/**
|
|
88
|
+
* Send a message over udp
|
|
89
|
+
*
|
|
90
|
+
* @param string message The message to send
|
|
91
|
+
* @param Function callback The callback for if there are any errors
|
|
92
|
+
*
|
|
93
|
+
* @return void
|
|
94
|
+
*/
|
|
95
|
+
private sendUdp;
|
|
96
|
+
private process;
|
|
97
|
+
}
|
|
98
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const events_1 = require("events");
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const LightwaveRFClient_1 = require("./LightwaveRFClient");
|
|
9
|
+
const LightwaveAccount_1 = require("./LightwaveAccount");
|
|
10
|
+
class LightwaveRFConfiguration {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.timeout = 1000;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** * LightwaveRF API
|
|
16
|
+
*
|
|
17
|
+
* @param object config The config
|
|
18
|
+
*
|
|
19
|
+
* An instance of the LightwaveRF API
|
|
20
|
+
*/
|
|
21
|
+
class LightwaveRF extends events_1.EventEmitter {
|
|
22
|
+
constructor(config, callback) {
|
|
23
|
+
super();
|
|
24
|
+
this.timeout = 1000;
|
|
25
|
+
this.queue = [];
|
|
26
|
+
this.ready = true;
|
|
27
|
+
this.awaitRegistrration = false;
|
|
28
|
+
this.currentTransactionNumber = 4674773;
|
|
29
|
+
this.devices = [];
|
|
30
|
+
this.messageCounter = 0;
|
|
31
|
+
this.config = {};
|
|
32
|
+
this.responseListeners = new Map();
|
|
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
|
+
});
|
|
40
|
+
this.timeout = config.timeout || 1000;
|
|
41
|
+
this.devices = []; //[{roomId:0,roomName:'',
|
|
42
|
+
//deviceId:0,deviceName:'',
|
|
43
|
+
//deviceType:''}];
|
|
44
|
+
//Config
|
|
45
|
+
this.config = config;
|
|
46
|
+
const self = this;
|
|
47
|
+
this.lwClient.on('deviceTurnedOn', function () {
|
|
48
|
+
self.emit('deviceTurnedOn', ...arguments);
|
|
49
|
+
});
|
|
50
|
+
this.lwClient.on('deviceTurnedOff', function () {
|
|
51
|
+
self.emit('deviceTurnedOff', ...arguments);
|
|
52
|
+
});
|
|
53
|
+
this.lwClient.on('deviceDimmed', function () {
|
|
54
|
+
self.emit('deviceDimmed', ...arguments);
|
|
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
|
+
// })
|
|
132
|
+
process.on('SIGINT', () => {
|
|
133
|
+
this.stop();
|
|
134
|
+
this.lwClient.stop();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
stop() {
|
|
138
|
+
this.debug("Stopping server sockets");
|
|
139
|
+
}
|
|
140
|
+
initialiseConfiguration(callback) {
|
|
141
|
+
//Check config
|
|
142
|
+
const lwAccount = new LightwaveAccount_1.LightwaveAccount(this.debug, this.lwClient, this.config.email, this.config.pin);
|
|
143
|
+
lwAccount.getConfiguration(callback);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Register this device with the Wi-Fi Link
|
|
147
|
+
*
|
|
148
|
+
* @param Function callback The callback function
|
|
149
|
+
*
|
|
150
|
+
* @return void
|
|
151
|
+
*/
|
|
152
|
+
register(callback) {
|
|
153
|
+
this.awaitRegistrration = true;
|
|
154
|
+
this.sendUdp("!F*p", callback);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Turn a device off
|
|
158
|
+
*
|
|
159
|
+
* @param integer roomId The room ID
|
|
160
|
+
* @param integer deviceId The device ID
|
|
161
|
+
* @param Function callback The callback for if there are any errors
|
|
162
|
+
*
|
|
163
|
+
* @return void
|
|
164
|
+
*/
|
|
165
|
+
turnDeviceOff(roomId, deviceId, callback) {
|
|
166
|
+
var state = "0";
|
|
167
|
+
this.exec("!R" + roomId + "D" + deviceId + "F" + state + "|\0", callback);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Turn a device on
|
|
171
|
+
*
|
|
172
|
+
* @param integer roomId The room ID
|
|
173
|
+
* @param integer deviceId The device ID
|
|
174
|
+
* @param Function callback The callback for if there are any errors
|
|
175
|
+
*
|
|
176
|
+
* @return void
|
|
177
|
+
*/
|
|
178
|
+
turnDeviceOn(roomId, deviceId, callback) {
|
|
179
|
+
// this.devices.find(d => d.roomId == roomId && d.deviceId == deviceId)?.turnOn();
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Set the dim percentage of a device
|
|
183
|
+
*
|
|
184
|
+
* @param integer roomId The room ID
|
|
185
|
+
* @param integer deviceId The device ID
|
|
186
|
+
* @param integer dimPercentage The percentage to set the device dim
|
|
187
|
+
* @param Function callback The callback for if there are any errors
|
|
188
|
+
*
|
|
189
|
+
* @return void
|
|
190
|
+
*/
|
|
191
|
+
setDeviceDim(roomId, deviceId, dimPercentage, callback) {
|
|
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
|
+
// }
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get message code
|
|
201
|
+
*
|
|
202
|
+
* @return string
|
|
203
|
+
*/
|
|
204
|
+
getTransactionNumber() {
|
|
205
|
+
return this.currentTransactionNumber;
|
|
206
|
+
}
|
|
207
|
+
exec(...args) {
|
|
208
|
+
// Check if the queue has a reasonable size
|
|
209
|
+
if (this.queue.length > 100) {
|
|
210
|
+
this.queue.pop();
|
|
211
|
+
}
|
|
212
|
+
this.debug("Ading to queue: " + args.join(" "));
|
|
213
|
+
this.queue.push(args);
|
|
214
|
+
this.process();
|
|
215
|
+
}
|
|
216
|
+
;
|
|
217
|
+
send(cmd, callback) {
|
|
218
|
+
this.sendUdp(cmd, callback);
|
|
219
|
+
//if (callback) callback();
|
|
220
|
+
}
|
|
221
|
+
;
|
|
222
|
+
/**
|
|
223
|
+
* Send a message over udp
|
|
224
|
+
*
|
|
225
|
+
* @param string message The message to send
|
|
226
|
+
* @param Function callback The callback for if there are any errors
|
|
227
|
+
*
|
|
228
|
+
* @return void
|
|
229
|
+
*/
|
|
230
|
+
sendUdp(message, callback) {
|
|
231
|
+
//Add to message
|
|
232
|
+
const transactionNumber = this.getTransactionNumber();
|
|
233
|
+
//Prepend code to message
|
|
234
|
+
message = `${transactionNumber},${message}`;
|
|
235
|
+
this.debug(`[${this.config.ip}][trans: ${transactionNumber}] Sending message: ${message}`);
|
|
236
|
+
//Create buffer from message
|
|
237
|
+
const messageBuffer = Buffer.from(message, 'utf-8');
|
|
238
|
+
this.debug("Callback for message: " + message, callback);
|
|
239
|
+
//Add listener
|
|
240
|
+
if (callback) {
|
|
241
|
+
this.debug("Registering call back with transaction number: " + transactionNumber);
|
|
242
|
+
this.responseListeners.set(transactionNumber, {
|
|
243
|
+
time: new Date().getTime(),
|
|
244
|
+
listener: callback
|
|
245
|
+
});
|
|
246
|
+
this.debug(this.responseListeners);
|
|
247
|
+
// Expire request, trigger retry
|
|
248
|
+
setTimeout(() => {
|
|
249
|
+
const listener = this.responseListeners.get(transactionNumber);
|
|
250
|
+
if (listener) {
|
|
251
|
+
this.debug(`[Transaction $(transactionNumber)] The listener is still there, triggering error`);
|
|
252
|
+
this.responseListeners.delete(transactionNumber);
|
|
253
|
+
callback("ERR:EXPIRED", undefined);
|
|
254
|
+
}
|
|
255
|
+
}, 1000);
|
|
256
|
+
}
|
|
257
|
+
//Broadcast the message
|
|
258
|
+
// this.sendSocket.send(messageBuffer, 0, messageBuffer.length, 9760, this.config.ip);
|
|
259
|
+
}
|
|
260
|
+
process() {
|
|
261
|
+
this.debug("Checking queue");
|
|
262
|
+
if (this.queue.length === 0)
|
|
263
|
+
return;
|
|
264
|
+
if (!this.ready)
|
|
265
|
+
return;
|
|
266
|
+
var self = this;
|
|
267
|
+
this.ready = false;
|
|
268
|
+
this.debug("Processing queue...");
|
|
269
|
+
this.debug("Items in the queue", this.queue.length);
|
|
270
|
+
this.send.apply(this, this.queue.shift());
|
|
271
|
+
setTimeout(function () {
|
|
272
|
+
self.ready = true;
|
|
273
|
+
self.process();
|
|
274
|
+
}, this.timeout);
|
|
275
|
+
}
|
|
276
|
+
;
|
|
277
|
+
}
|
|
278
|
+
exports.default = LightwaveRF;
|
package/package.json
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evops/lightwaverf",
|
|
3
3
|
"description": "Lightwave RF client library",
|
|
4
|
-
"version": "0.0.
|
|
5
|
-
"main": "index.js",
|
|
4
|
+
"version": "0.0.8",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
6
7
|
"bin": "bin/lightwaverf.js",
|
|
7
8
|
"scripts": {
|
|
8
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
10
|
+
"prepublish": "tsc"
|
|
9
11
|
},
|
|
10
12
|
"repository": {
|
|
11
13
|
"type": "git",
|
|
12
|
-
"url": "git://github.com/
|
|
14
|
+
"url": "git://github.com/eu-evos/node-lightwaverf.git"
|
|
13
15
|
},
|
|
14
16
|
"keywords": [
|
|
15
17
|
"lightwaverf"
|
|
16
18
|
],
|
|
17
|
-
"author": "
|
|
18
|
-
"license": "
|
|
19
|
+
"author": "Stanislaw Wozniak",
|
|
20
|
+
"license": "MIT",
|
|
19
21
|
"bugs": {
|
|
20
|
-
"url": "https://github.com/
|
|
22
|
+
"url": "https://github.com/eu-evos/node-lightwaverf/issues"
|
|
21
23
|
},
|
|
22
24
|
"dependencies": {
|
|
23
|
-
"debug": "
|
|
25
|
+
"@types/debug": "^4.1.7",
|
|
26
|
+
"@types/js-yaml": "^4.0.5",
|
|
27
|
+
"@types/request-promise": "^4.1.48",
|
|
28
|
+
"debug": "4.3.3",
|
|
24
29
|
"js-yaml": ">=3.5.3",
|
|
25
30
|
"request": "^2.74.0",
|
|
26
|
-
"request-promise": "^4.1.1"
|
|
27
|
-
"wait.for": ">=0.6.6"
|
|
31
|
+
"request-promise": "^4.1.1"
|
|
28
32
|
}
|
|
29
|
-
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import Debug, { Debugger } from "debug";
|
|
2
|
+
import { RequestAPI, RequiredUriUrl } from "request";
|
|
3
|
+
import rp from "request-promise";
|
|
4
|
+
import { LightwaveDevice, LightwaveDeviceType } from "./LightwaveDevice";
|
|
5
|
+
import { LightwaveRFClient } from "./LightwaveRFClient";
|
|
6
|
+
|
|
7
|
+
export class LightwaveAccount {
|
|
8
|
+
debug: Debug.Debugger;
|
|
9
|
+
client: LightwaveRFClient;
|
|
10
|
+
email: string;
|
|
11
|
+
pin: string;
|
|
12
|
+
mainDebug: Debug.Debugger;
|
|
13
|
+
|
|
14
|
+
constructor(debug: Debugger, client: LightwaveRFClient, email: string, pin: string) {
|
|
15
|
+
if (!email || !pin) {
|
|
16
|
+
throw "No email or pin specified. The server configuration (rooms, devices, etc.) cannot be obtained";
|
|
17
|
+
}
|
|
18
|
+
this.mainDebug = debug;
|
|
19
|
+
this.debug = debug.extend('account');
|
|
20
|
+
this.client = client;
|
|
21
|
+
this.email = email;
|
|
22
|
+
this.pin = pin;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getConfiguration(callback: any) {
|
|
26
|
+
this.debug('Getting rooms from LightWave');
|
|
27
|
+
var self = this;
|
|
28
|
+
var host = 'https://control-api.lightwaverf.com';
|
|
29
|
+
var json = rp.defaults({
|
|
30
|
+
json: true
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
var auth: RequestAPI<rp.RequestPromise<any>, rp.RequestPromiseOptions, RequiredUriUrl>, token;
|
|
34
|
+
json.get(host + '/v1/user?password=' + this.pin + '&username=' + this.email)
|
|
35
|
+
.then(function (res) {
|
|
36
|
+
return json.get(host + '/v1/auth?application_key=' + res.application_key)
|
|
37
|
+
})
|
|
38
|
+
.then(function (res) {
|
|
39
|
+
token = res.token;
|
|
40
|
+
auth = json.defaults({
|
|
41
|
+
headers: {
|
|
42
|
+
'X-LWRF-token': token,
|
|
43
|
+
'X-LWRF-platform': 'ios',
|
|
44
|
+
'X-LWRF-skin': 'lightwaverf'
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return auth.get(host + '/v1/device_type?nested=1');
|
|
49
|
+
})
|
|
50
|
+
.then(function (res) {
|
|
51
|
+
return auth.get(host + '/v1/user_profile?nested=1')
|
|
52
|
+
})
|
|
53
|
+
.then(function (res) {
|
|
54
|
+
self.parseRooms(res, callback);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
parseRooms(lightwaveResponse: any, callback: (devices: LightwaveDevice[], error: Error | null) => void) {
|
|
60
|
+
this.debug('Parsing lightwaveResponse: ',
|
|
61
|
+
lightwaveResponse.content.estates[0].locations[0].zones[0].rooms[0].devices);
|
|
62
|
+
|
|
63
|
+
const home = lightwaveResponse.content.estates[0].locations[0].zones[0];
|
|
64
|
+
const devices = [];
|
|
65
|
+
|
|
66
|
+
for (var i = 0; i < home.rooms.length; i++) {
|
|
67
|
+
var r = home.rooms[i];
|
|
68
|
+
|
|
69
|
+
this.debug("Room " + r.name + " with " + r.devices.length + " devices");
|
|
70
|
+
|
|
71
|
+
// Get device types
|
|
72
|
+
// O: On/Off Switch
|
|
73
|
+
// D: Dimmer
|
|
74
|
+
// R: Radiator(s)
|
|
75
|
+
// P: Open/Close
|
|
76
|
+
// I: Inactive (i.e. not configured)
|
|
77
|
+
// m: Mood (inactive)
|
|
78
|
+
// M: Mood (active)
|
|
79
|
+
// o: All Off
|
|
80
|
+
var deviceTypeMapping: Map<number, LightwaveDeviceType> = new Map<number, LightwaveDeviceType>();
|
|
81
|
+
deviceTypeMapping.set(1, LightwaveDeviceType.OnOff);
|
|
82
|
+
deviceTypeMapping.set(2, LightwaveDeviceType.Dimmer);
|
|
83
|
+
deviceTypeMapping.set(3, LightwaveDeviceType.OnOff);
|
|
84
|
+
|
|
85
|
+
for (var j = 0; j < r.devices.length; j++) {
|
|
86
|
+
var d = r.devices[j];
|
|
87
|
+
|
|
88
|
+
const device = new LightwaveDevice(
|
|
89
|
+
this.client,
|
|
90
|
+
this.mainDebug,
|
|
91
|
+
r.room_number,
|
|
92
|
+
d.device_number,
|
|
93
|
+
r.name,
|
|
94
|
+
d.name,
|
|
95
|
+
deviceTypeMapping.get(d.device_type_id)!
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
devices.push(device);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.debug('Devices: %O', devices)
|
|
103
|
+
|
|
104
|
+
callback(devices, null);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import Debug from 'debug';
|
|
2
|
+
import { LightwaveRFClient } from './LightwaveRFClient';
|
|
3
|
+
|
|
4
|
+
export interface LightwaveRFDeviceInterface {
|
|
5
|
+
roomId: number
|
|
6
|
+
deviceId: number
|
|
7
|
+
roomName: string
|
|
8
|
+
deviceName: string
|
|
9
|
+
deviceType: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export enum LightwaveDeviceType {
|
|
13
|
+
Dimmer = "D",
|
|
14
|
+
OnOff = "O",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class LightwaveDevice implements LightwaveRFDeviceInterface {
|
|
18
|
+
roomId: number;
|
|
19
|
+
deviceId: number;
|
|
20
|
+
roomName: string;
|
|
21
|
+
deviceName: string;
|
|
22
|
+
deviceType: LightwaveDeviceType;
|
|
23
|
+
client: LightwaveRFClient;
|
|
24
|
+
debug: Debug.Debugger;
|
|
25
|
+
|
|
26
|
+
constructor(client: LightwaveRFClient, debug: debug.Debugger, roomId: number, deviceId: number, roomName: string, deviceName: string, deviceType: LightwaveDeviceType) {
|
|
27
|
+
this.client = client;
|
|
28
|
+
this.debug = debug.extend(deviceName);
|
|
29
|
+
this.roomId = roomId;
|
|
30
|
+
this.deviceId = deviceId;
|
|
31
|
+
this.roomName = roomName;
|
|
32
|
+
this.deviceName = deviceName;
|
|
33
|
+
this.deviceType = deviceType;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async turnOn(): Promise<void> {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
this.debug("Device turning on");
|
|
39
|
+
this.client.send(`R${this.roomId}D${this.deviceId}F1`, (message, error) => {
|
|
40
|
+
resolve();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async turnOff(): Promise<void> {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
this.debug("Device turning off");
|
|
48
|
+
this.client.send(`R${this.roomId}D${this.deviceId}F0`, (message, error) => {
|
|
49
|
+
if (error) return reject(error);
|
|
50
|
+
resolve();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async dim(percentage: number): Promise<void> {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
this.debug("Device dimming to %d", percentage);
|
|
58
|
+
|
|
59
|
+
const lwDim = Math.round(percentage * 0.32);
|
|
60
|
+
this.client.send(`R${this.roomId}D${this.deviceId}FdP${lwDim}`, (message, error) => {
|
|
61
|
+
if (error) return reject(error);
|
|
62
|
+
resolve();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Debugger } from "debug";
|
|
2
|
+
import "./LightwaveTransaction";
|
|
3
|
+
import { LightwaveTransaction } from "./LightwaveTransaction";
|
|
4
|
+
import LightwaveMessageProcessor from "./LightwaveMessageProcessor";
|
|
5
|
+
|
|
6
|
+
export class LightwaveJsonMessageProcessor implements LightwaveMessageProcessor {
|
|
7
|
+
debug: Debugger;
|
|
8
|
+
constructor(debug: Debugger) {
|
|
9
|
+
this.debug = debug.extend('jsonMessageProcessor');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
process(message: Buffer): any {
|
|
13
|
+
this.debug('Processing message')
|
|
14
|
+
const textMessage = message.toString('utf-8').replace('*!', '');
|
|
15
|
+
const json = JSON.parse(textMessage);
|
|
16
|
+
|
|
17
|
+
const response = json;
|
|
18
|
+
response.id = json.trans;
|
|
19
|
+
response.error = json.error ?? null;
|
|
20
|
+
|
|
21
|
+
return response;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
canProcess(message: Buffer): boolean {
|
|
25
|
+
this.debug("Checking if can process message");
|
|
26
|
+
return message.toString('utf-8').startsWith('*!');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|