@evops/lightwaverf 0.0.5 → 0.0.9

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.
@@ -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,32 @@
1
1
  {
2
2
  "name": "@evops/lightwaverf",
3
3
  "description": "Lightwave RF client library",
4
- "version": "0.0.5",
5
- "main": "index.js",
6
- "bin": "bin/lightwaverf.js",
4
+ "version": "0.0.9",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
7
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "prepublish": "tsc"
9
10
  },
10
11
  "repository": {
11
12
  "type": "git",
12
- "url": "git://github.com/ollieparsley/node-lightwaverf.git"
13
+ "url": "git://github.com/eu-evos/node-lightwaverf.git"
13
14
  },
14
15
  "keywords": [
15
16
  "lightwaverf"
16
17
  ],
17
- "author": "Ollie Parsley",
18
- "license": "BSD-2-Clause",
18
+ "author": "Stanislaw Wozniak",
19
+ "license": "MIT",
19
20
  "bugs": {
20
- "url": "https://github.com/ollieparsley/node-lightwaverf/issues"
21
+ "url": "https://github.com/eu-evos/node-lightwaverf/issues"
21
22
  },
22
23
  "dependencies": {
23
- "debug": "~2.2.0",
24
+ "@types/debug": "^4.1.7",
25
+ "@types/js-yaml": "^4.0.5",
26
+ "@types/request-promise": "^4.1.48",
27
+ "debug": "4.3.3",
24
28
  "js-yaml": ">=3.5.3",
25
29
  "request": "^2.74.0",
26
- "request-promise": "^4.1.1",
27
- "wait.for": ">=0.6.6"
30
+ "request-promise": "^4.1.1"
28
31
  }
29
32
  }
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ import "./LightwaveTransaction";
2
+
3
+ declare interface LightwaveMessageProcessor {
4
+ process(message: Buffer): any;
5
+ canProcess(message: Buffer): boolean;
6
+ }
7
+
8
+ export default LightwaveMessageProcessor;