zwave-js-ui 9.3.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.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -0
  3. package/dev-dist/registerSW.js +5 -0
  4. package/dist/apple-touch-icon-180x180.png +0 -0
  5. package/dist/assets/AssociationGroups-474358b5.js +1 -0
  6. package/dist/assets/BgRssiChart-3e7d7555.css +1 -0
  7. package/dist/assets/BgRssiChart-554c89ef.js +3 -0
  8. package/dist/assets/BlinkIcon-5407e2e0.js +1 -0
  9. package/dist/assets/ColumnFilter-378ec338.js +1 -0
  10. package/dist/assets/ColumnFilterBoolean-e0ff8ce6.js +1 -0
  11. package/dist/assets/ColumnFilterDate-b17871ea.js +1 -0
  12. package/dist/assets/ColumnFilterNumber-c07930a6.js +1 -0
  13. package/dist/assets/ColumnFilterString-079ac562.js +1 -0
  14. package/dist/assets/ControlPanel-3c3168d8.js +7 -0
  15. package/dist/assets/ControllerChart-f2fbb771.js +1 -0
  16. package/dist/assets/Debug-ea34e06e.js +98 -0
  17. package/dist/assets/DialogAdvanced-5f8c36c7.js +1 -0
  18. package/dist/assets/DialogAdvanced-eaabda04.css +1 -0
  19. package/dist/assets/DialogAssociation-6da4cd66.js +1 -0
  20. package/dist/assets/DialogGatewayValue-501b7bbe.js +1 -0
  21. package/dist/assets/DialogGatewayValue-911dd212.css +1 -0
  22. package/dist/assets/DialogHealthCheck-2228ed6c.css +1 -0
  23. package/dist/assets/DialogHealthCheck-9e90523a.js +1 -0
  24. package/dist/assets/DialogSceneValue-ff3081b9.js +1 -0
  25. package/dist/assets/ErrorPage-a4f837c6.js +1 -0
  26. package/dist/assets/ExpandedNode-9f727a42.css +1 -0
  27. package/dist/assets/ExpandedNode-a0bff765.js +3 -0
  28. package/dist/assets/HomeAssistant-974143e2.js +1 -0
  29. package/dist/assets/ListInput-d8c678f2.js +1 -0
  30. package/dist/assets/Login-1826b0a1.css +1 -0
  31. package/dist/assets/Login-5424b4df.js +1 -0
  32. package/dist/assets/MaterialIcons-Regular-11ec382a.woff +0 -0
  33. package/dist/assets/MaterialIcons-Regular-29c11fa5.ttf +0 -0
  34. package/dist/assets/MaterialIcons-Regular-5743ed3d.woff2 +0 -0
  35. package/dist/assets/MaterialIcons-Regular-e69d687a.eot +0 -0
  36. package/dist/assets/Mesh-1b8d31eb.css +1 -0
  37. package/dist/assets/Mesh-25b19dfe.js +1 -0
  38. package/dist/assets/NodeDetails-da00c417.css +1 -0
  39. package/dist/assets/NodeDetails-e9d8d566.js +5 -0
  40. package/dist/assets/NodePanel-3639f227.css +1 -0
  41. package/dist/assets/NodePanel-5cdb1b4a.js +1 -0
  42. package/dist/assets/NodeScheduler-e91e411b.js +1 -0
  43. package/dist/assets/OTAUpdates-066cbfed.js +7 -0
  44. package/dist/assets/QrReader-00dee3fb.css +1 -0
  45. package/dist/assets/QrReader-c320584c.js +1 -0
  46. package/dist/assets/ReinterviewBadge-a40fb19f.js +1 -0
  47. package/dist/assets/RichValue-3ea76a33.css +1 -0
  48. package/dist/assets/RichValue-3f78fa98.js +1 -0
  49. package/dist/assets/Scenes-4aea74b8.js +1 -0
  50. package/dist/assets/Settings-ac079344.css +1 -0
  51. package/dist/assets/Settings-d8e203ed.js +44 -0
  52. package/dist/assets/SmartStart-63c21be6.js +2 -0
  53. package/dist/assets/SmartView-f9259d20.js +1 -0
  54. package/dist/assets/StatisticsArrows-40c56587.js +1 -0
  55. package/dist/assets/StatisticsCard-a91596c0.js +1 -0
  56. package/dist/assets/Store-701d51c8.js +1 -0
  57. package/dist/assets/Store-a58f7130.css +1 -0
  58. package/dist/assets/UserCodeTable-c397703b.js +1 -0
  59. package/dist/assets/ValueId-b8e1e4a2.js +1 -0
  60. package/dist/assets/ValueId-ea679e64.css +1 -0
  61. package/dist/assets/ZwaveGraph-4fa851e3.js +98 -0
  62. package/dist/assets/ZwaveGraph-fe07d4ee.css +1 -0
  63. package/dist/assets/file-input-064e7979.js +1 -0
  64. package/dist/assets/index-058391ec.js +17 -0
  65. package/dist/assets/index-3c63af0b.js +112 -0
  66. package/dist/assets/index-468a52af.js +2 -0
  67. package/dist/assets/index-be785cef.css +9 -0
  68. package/dist/assets/index-d98f5afd.css +1 -0
  69. package/dist/assets/items-45b4c1f5.js +1 -0
  70. package/dist/assets/mdi-4fe99e39.js +1 -0
  71. package/dist/assets/prismeditor.esm-3002a813.js +7 -0
  72. package/dist/assets/qr-scanner-worker.min-5f44a019.js +98 -0
  73. package/dist/assets/vuedraggable.umd-441070b9.js +8 -0
  74. package/dist/favicon.ico +0 -0
  75. package/dist/index.html +47 -0
  76. package/dist/logo.png +0 -0
  77. package/dist/logo.svg +32 -0
  78. package/dist/manifest.webmanifest +1 -0
  79. package/dist/maskable-icon-512x512.png +0 -0
  80. package/dist/pwa-192x192.png +0 -0
  81. package/dist/pwa-512x512.png +0 -0
  82. package/dist/pwa-64x64.png +0 -0
  83. package/dist/registerSW.js +1 -0
  84. package/dist/star.svg +3 -0
  85. package/dist/sw.js +1232 -0
  86. package/package.json +217 -0
  87. package/public/apple-touch-icon-180x180.png +0 -0
  88. package/public/favicon.ico +0 -0
  89. package/public/logo.png +0 -0
  90. package/public/logo.svg +32 -0
  91. package/public/maskable-icon-512x512.png +0 -0
  92. package/public/pwa-192x192.png +0 -0
  93. package/public/pwa-512x512.png +0 -0
  94. package/public/pwa-64x64.png +0 -0
  95. package/public/star.svg +3 -0
  96. package/server/app.js +1201 -0
  97. package/server/bin/www.js +70 -0
  98. package/server/config/app.js +22 -0
  99. package/server/config/store.js +19 -0
  100. package/server/hass/configurations.js +195 -0
  101. package/server/hass/devices.js +397 -0
  102. package/server/lib/BackupManager.js +134 -0
  103. package/server/lib/Constants.js +705 -0
  104. package/server/lib/CustomPlugin.js +9 -0
  105. package/server/lib/EventEmitter.js +14 -0
  106. package/server/lib/Gateway.js +1986 -0
  107. package/server/lib/MqttClient.js +418 -0
  108. package/server/lib/SocketEvents.js +34 -0
  109. package/server/lib/SocketManager.js +71 -0
  110. package/server/lib/ZwaveClient.js +4261 -0
  111. package/server/lib/jsonStore.js +139 -0
  112. package/server/lib/logger.js +169 -0
  113. package/server/lib/utils.js +283 -0
  114. package/snippets/access-store-dir.js +12 -0
  115. package/snippets/clone-config.js +17 -0
  116. package/snippets/pingNodes.js +14 -0
  117. package/snippets/reinterview-nodes.js +64 -0
@@ -0,0 +1,418 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const mqtt_1 = require("mqtt");
4
+ const utils_1 = require("./utils");
5
+ const logger_1 = require("./logger");
6
+ const EventEmitter_1 = require("./EventEmitter");
7
+ const app_1 = require("../config/app");
8
+ const fs_extra_1 = require("fs-extra");
9
+ const mqtt_jsonl_store_1 = require("mqtt-jsonl-store");
10
+ const path_1 = require("path");
11
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
12
+ const url = require('native-url');
13
+ const logger = (0, logger_1.module)('Mqtt');
14
+ class MqttClient extends EventEmitter_1.TypedEventEmitter {
15
+ config;
16
+ toSubscribe;
17
+ _clientID;
18
+ client;
19
+ error;
20
+ closed;
21
+ retrySubTimeout;
22
+ _closeTimeout;
23
+ storeManager;
24
+ static CLIENTS_PREFIX = '_CLIENTS';
25
+ static get EVENTS_PREFIX() {
26
+ return '_EVENTS';
27
+ }
28
+ static NAME_PREFIX = 'ZWAVE_GATEWAY-';
29
+ static ACTIONS = ['broadcast', 'api', 'multicast'];
30
+ static HASS_WILL = 'homeassistant/status';
31
+ static STATUS_TOPIC = 'status';
32
+ static VERSION_TOPIC = 'version';
33
+ get clientID() {
34
+ return this._clientID;
35
+ }
36
+ /**
37
+ * The constructor
38
+ */
39
+ constructor(config) {
40
+ super();
41
+ this._init(config).catch((e) => {
42
+ logger.error('Error while initializing MQTT Client', e);
43
+ });
44
+ }
45
+ get connected() {
46
+ return this.client && this.client.connected;
47
+ }
48
+ get disabled() {
49
+ return this.config.disabled;
50
+ }
51
+ /**
52
+ * Returns the topic used to send client and devices status updateStates
53
+ * if name is null the client is the gateway itself
54
+ */
55
+ getClientTopic(suffix) {
56
+ return `${this.config.prefix}/${MqttClient.CLIENTS_PREFIX}/${this._clientID}/${suffix}`;
57
+ }
58
+ /**
59
+ * Method used to close clients connection, use this before destroy
60
+ */
61
+ close() {
62
+ return new Promise((resolve) => {
63
+ if (this.closed) {
64
+ resolve();
65
+ return;
66
+ }
67
+ this.closed = true;
68
+ if (this.retrySubTimeout) {
69
+ clearTimeout(this.retrySubTimeout);
70
+ this.retrySubTimeout = null;
71
+ }
72
+ let resolved = false;
73
+ if (this.client) {
74
+ const onClose = async (error) => {
75
+ // prevent multiple resolve
76
+ if (resolved) {
77
+ return;
78
+ }
79
+ resolved = true;
80
+ // fix error:Failed to lock DB file when force closing
81
+ await this.storeManager?.close();
82
+ if (this._closeTimeout) {
83
+ clearTimeout(this._closeTimeout);
84
+ this._closeTimeout = null;
85
+ }
86
+ if (error) {
87
+ logger.error('Error while closing client', error);
88
+ }
89
+ this.removeAllListeners();
90
+ logger.info('Client closed');
91
+ resolve();
92
+ };
93
+ this.client.end(false, {}, onClose);
94
+ // in case a clean close doesn't work, force close
95
+ this._closeTimeout = setTimeout(() => {
96
+ this.client.end(true, {}, onClose);
97
+ }, 5000);
98
+ }
99
+ else {
100
+ this.removeAllListeners();
101
+ resolve();
102
+ }
103
+ });
104
+ }
105
+ /**
106
+ * Method used to get status
107
+ */
108
+ getStatus() {
109
+ const status = {};
110
+ status.status = this.client && this.client.connected;
111
+ status.error = this.error || 'Offline';
112
+ status.config = this.config;
113
+ return status;
114
+ }
115
+ /**
116
+ * Method used to update client connection status
117
+ */
118
+ updateClientStatus(connected) {
119
+ if (this.client) {
120
+ this.client.publish(this.getClientTopic(MqttClient.STATUS_TOPIC), JSON.stringify({ value: connected, time: Date.now() }), { retain: this.config.retain, qos: this.config.qos });
121
+ }
122
+ }
123
+ /**
124
+ * Method used to publish app version to mqtt
125
+ */
126
+ publishVersion() {
127
+ if (this.client) {
128
+ this.client.publish(this.getClientTopic(MqttClient.VERSION_TOPIC), JSON.stringify({ value: utils_1.pkgJson.version, time: Date.now() }), { retain: this.config.retain, qos: this.config.qos });
129
+ }
130
+ }
131
+ /**
132
+ * Method used to update client
133
+ */
134
+ async update(config) {
135
+ await this.close();
136
+ logger.info('Restarting Mqtt Client after update...');
137
+ await this._init(config);
138
+ }
139
+ /**
140
+ * Method used to subscribe tags for write requests
141
+ */
142
+ subscribe(topic, options = {
143
+ qos: 1,
144
+ addPrefix: true,
145
+ }) {
146
+ return new Promise((resolve, reject) => {
147
+ const subOptions = {
148
+ qos: options.qos,
149
+ };
150
+ topic = options.addPrefix
151
+ ? this.config.prefix + '/' + topic + '/set'
152
+ : topic;
153
+ options.addPrefix = false; // in case of retry, don't add again the prefix
154
+ if (this.client && this.client.connected) {
155
+ logger.log('debug', `Subscribing to ${topic} with options %o`, subOptions);
156
+ this.client.subscribe(topic, subOptions, (err, granted) => {
157
+ if (err) {
158
+ logger.error(`Error subscribing to ${topic}`, err);
159
+ this.toSubscribe.set(topic, options);
160
+ reject(err);
161
+ }
162
+ else {
163
+ for (const res of granted) {
164
+ if (res.qos === 128) {
165
+ logger.error(`Error subscribing to ${topic}, client doesn't have permission to subscribe to it`);
166
+ }
167
+ else {
168
+ logger.info(`Subscribed to ${topic}`);
169
+ }
170
+ this.toSubscribe.delete(topic);
171
+ }
172
+ resolve();
173
+ }
174
+ });
175
+ }
176
+ else {
177
+ logger.debug(`Client not connected yet, subscribing to ${topic} later...`);
178
+ this.toSubscribe.set(topic, options);
179
+ reject(Error('Client not connected'));
180
+ }
181
+ });
182
+ }
183
+ /**
184
+ * Method used to publish an update
185
+ */
186
+ publish(topic, data, options, prefix) {
187
+ if (this.client) {
188
+ const settingOptions = {
189
+ qos: this.config.qos,
190
+ retain: this.config.retain,
191
+ };
192
+ // by default use settingsOptions
193
+ options = Object.assign(settingOptions, options);
194
+ topic = (prefix || this.config.prefix) + '/' + topic;
195
+ logger.log('debug', 'Publishing to %s: %o with options %o', topic, data, options);
196
+ this.client.publish(topic, JSON.stringify(data), options, function (err) {
197
+ if (err) {
198
+ logger.error(`Error while publishing a value ${err.message}`);
199
+ }
200
+ });
201
+ } // end if client
202
+ }
203
+ /**
204
+ * Method used to get the topic with prefix/suffix
205
+ */
206
+ getTopic(topic, set = false) {
207
+ return this.config.prefix + '/' + topic + (set ? '/set' : '');
208
+ }
209
+ /**
210
+ * Initialize client
211
+ */
212
+ async _init(config) {
213
+ this.config = config;
214
+ this.toSubscribe = new Map();
215
+ if (!config || config.disabled) {
216
+ logger.info('MQTT is disabled');
217
+ return;
218
+ }
219
+ this._clientID = (0, utils_1.sanitizeTopic)(MqttClient.NAME_PREFIX + (process.env.MQTT_NAME || config.name));
220
+ const parsed = url.parse(config.host || '');
221
+ let protocol = 'mqtt';
222
+ if (parsed.protocol)
223
+ protocol = parsed.protocol.replace(/:$/, '');
224
+ const options = {
225
+ clientId: this._clientID,
226
+ reconnectPeriod: config.reconnectPeriod,
227
+ clean: config.clean,
228
+ rejectUnauthorized: !config.allowSelfsigned,
229
+ will: {
230
+ topic: this.getClientTopic(MqttClient.STATUS_TOPIC),
231
+ payload: JSON.stringify({ value: false }),
232
+ qos: this.config.qos,
233
+ retain: this.config.retain,
234
+ },
235
+ };
236
+ if (['mqtts', 'wss', 'wxs', 'alis', 'tls'].indexOf(protocol) >= 0) {
237
+ if (!config.allowSelfsigned)
238
+ options.ca = config._ca;
239
+ if (config._key) {
240
+ options.key = config._key;
241
+ }
242
+ if (config._cert) {
243
+ options.cert = config._cert;
244
+ }
245
+ }
246
+ if (config.store) {
247
+ const dbDir = (0, path_1.join)(app_1.storeDir, 'mqtt-packets-store');
248
+ await (0, fs_extra_1.ensureDir)(dbDir);
249
+ this.storeManager = new mqtt_jsonl_store_1.Manager(dbDir);
250
+ await this.storeManager.open();
251
+ // no reason to use a memory store for incoming messages
252
+ options.incomingStore = this.storeManager
253
+ .incoming;
254
+ options.outgoingStore = this.storeManager
255
+ .outgoing;
256
+ }
257
+ if (config.auth) {
258
+ options.username = config.username;
259
+ options.password = config.password;
260
+ }
261
+ try {
262
+ const serverUrl = `${protocol}://${parsed.hostname || config.host}:${config.port}`;
263
+ logger.info(`Connecting to ${serverUrl}`);
264
+ const client = (0, mqtt_1.connect)(serverUrl, options);
265
+ this.client = client;
266
+ client.on('connect', this._onConnect.bind(this));
267
+ client.on('message', this._onMessageReceived.bind(this));
268
+ client.on('reconnect', this._onReconnect.bind(this));
269
+ client.on('close', this._onClose.bind(this));
270
+ client.on('error', this._onError.bind(this));
271
+ client.on('offline', this._onOffline.bind(this));
272
+ }
273
+ catch (e) {
274
+ logger.error(`Error while connecting MQTT ${e.message}`);
275
+ this.error = e.message;
276
+ }
277
+ }
278
+ /**
279
+ * Function called when MQTT client connects
280
+ */
281
+ async _onConnect() {
282
+ logger.info('MQTT client connected');
283
+ this.emit('connect');
284
+ const subscribePromises = [];
285
+ subscribePromises.push(this.subscribe(MqttClient.HASS_WILL, { addPrefix: false, qos: 1 }));
286
+ // subscribe to actions
287
+ for (let i = 0; i < MqttClient.ACTIONS.length; i++) {
288
+ subscribePromises.push(this.subscribe([
289
+ this.config.prefix,
290
+ MqttClient.CLIENTS_PREFIX,
291
+ this._clientID,
292
+ MqttClient.ACTIONS[i],
293
+ '#',
294
+ ].join('/'), { addPrefix: false, qos: 1 }));
295
+ }
296
+ await (0, utils_1.allSettled)(subscribePromises);
297
+ await this._retrySubscribe();
298
+ this.emit('brokerStatus', true);
299
+ this.publishVersion();
300
+ // Update client status
301
+ this.updateClientStatus(true);
302
+ }
303
+ /**
304
+ * Function called when MQTT client reconnects
305
+ */
306
+ _onReconnect() {
307
+ logger.info('MQTT client reconnecting');
308
+ }
309
+ /**
310
+ * Function called when MQTT client reconnects
311
+ */
312
+ _onError(error) {
313
+ logger.error('Mqtt client error', error);
314
+ this.error = error.message;
315
+ }
316
+ /**
317
+ * Function called when MQTT client go offline
318
+ */
319
+ _onOffline() {
320
+ if (this.retrySubTimeout) {
321
+ clearTimeout(this.retrySubTimeout);
322
+ this.retrySubTimeout = null;
323
+ }
324
+ logger.info('MQTT client offline');
325
+ this.emit('brokerStatus', false);
326
+ }
327
+ /**
328
+ * Function called when MQTT client is closed
329
+ */
330
+ _onClose() {
331
+ logger.info('MQTT client closed');
332
+ }
333
+ /**
334
+ * Function called when an MQTT message is received
335
+ */
336
+ _onMessageReceived(topic, payload) {
337
+ if (this.closed)
338
+ return;
339
+ let parsed = payload?.toString();
340
+ logger.log('info', `Message received on ${topic}: %o`, parsed);
341
+ if (topic === MqttClient.HASS_WILL) {
342
+ if (typeof parsed === 'string') {
343
+ this.emit('hassStatus', parsed.toLowerCase() === 'online');
344
+ }
345
+ else {
346
+ logger.error('Invalid payload sent to Hass Will topic');
347
+ }
348
+ return;
349
+ }
350
+ // remove prefix
351
+ topic = topic.substring(this.config.prefix.length + 1);
352
+ const parts = topic.split('/');
353
+ // It's not a write request
354
+ if (parts.pop() !== 'set')
355
+ return;
356
+ if (isNaN(parseInt(parsed))) {
357
+ try {
358
+ parsed = (0, utils_1.parseJSON)(parsed);
359
+ }
360
+ catch (e) {
361
+ // it' ok fallback to string
362
+ }
363
+ }
364
+ else {
365
+ parsed = Number(parsed);
366
+ }
367
+ // It's an action
368
+ if (parts[0] === MqttClient.CLIENTS_PREFIX) {
369
+ if (parts.length < 3)
370
+ return;
371
+ const action = MqttClient.ACTIONS.indexOf(parts[2]);
372
+ switch (action) {
373
+ case 0: // broadcast
374
+ this.emit('broadcastRequest', parts.slice(3), parsed);
375
+ // publish back to give a feedback the action has been received
376
+ // same topic without /set suffix
377
+ this.publish(parts.join('/'), parsed);
378
+ break;
379
+ case 1: // api
380
+ this.emit('apiCall', parts.join('/'), parts[3], parsed);
381
+ break;
382
+ case 2: // multicast
383
+ this.emit('multicastRequest', parsed);
384
+ // publish back to give a feedback the action has been received
385
+ // same topic without /set suffix
386
+ this.publish(parts.join('/'), parsed);
387
+ break;
388
+ default:
389
+ logger.warn(`Unknown action received ${action} ${topic}`);
390
+ }
391
+ }
392
+ else {
393
+ // It's a write request on zwave network
394
+ this.emit('writeRequest', parts, parsed);
395
+ }
396
+ } // end onMessageReceived
397
+ async _retrySubscribe() {
398
+ if (this.retrySubTimeout) {
399
+ clearTimeout(this.retrySubTimeout);
400
+ this.retrySubTimeout = null;
401
+ }
402
+ if (this.toSubscribe.size === 0) {
403
+ return;
404
+ }
405
+ logger.debug('Retry to subscribe to topics...');
406
+ const subscribePromises = [];
407
+ const topics = this.toSubscribe.keys();
408
+ for (const t of topics) {
409
+ subscribePromises.push(this.subscribe(t, this.toSubscribe.get(t)));
410
+ }
411
+ this.toSubscribe = new Map();
412
+ await (0, utils_1.allSettled)(subscribePromises);
413
+ if (this.toSubscribe.size > 0) {
414
+ this.retrySubTimeout = setTimeout(this._retrySubscribe.bind(this), 5000);
415
+ }
416
+ }
417
+ }
418
+ exports.default = MqttClient;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.inboundEvents = exports.socketEvents = void 0;
4
+ var socketEvents;
5
+ (function (socketEvents) {
6
+ socketEvents["init"] = "INIT";
7
+ socketEvents["controller"] = "CONTROLLER_CMD";
8
+ socketEvents["connected"] = "CONNECTED";
9
+ socketEvents["nodeFound"] = "NODE_FOUND";
10
+ socketEvents["nodeAdded"] = "NODE_ADDED";
11
+ socketEvents["nodeRemoved"] = "NODE_REMOVED";
12
+ socketEvents["nodeUpdated"] = "NODE_UPDATED";
13
+ socketEvents["valueUpdated"] = "VALUE_UPDATED";
14
+ socketEvents["valueRemoved"] = "VALUE_REMOVED";
15
+ socketEvents["metadataUpdated"] = "METADATA_UPDATED";
16
+ socketEvents["rebuildRoutesProgress"] = "REBUILD_ROUTES_PROGRESS";
17
+ socketEvents["healthCheckProgress"] = "HEALTH_CHECK_PROGRESS";
18
+ socketEvents["info"] = "INFO";
19
+ socketEvents["api"] = "API_RETURN";
20
+ socketEvents["debug"] = "DEBUG";
21
+ socketEvents["statistics"] = "STATISTICS";
22
+ socketEvents["nodeEvent"] = "NODE_EVENT";
23
+ socketEvents["grantSecurityClasses"] = "GRANT_SECURITY_CLASSES";
24
+ socketEvents["validateDSK"] = "VALIDATE_DSK";
25
+ socketEvents["inclusionAborted"] = "INCLUSION_ABORTED";
26
+ })(socketEvents || (exports.socketEvents = socketEvents = {}));
27
+ // events from client ---> server
28
+ var inboundEvents;
29
+ (function (inboundEvents) {
30
+ inboundEvents["init"] = "INITED";
31
+ inboundEvents["zwave"] = "ZWAVE_API";
32
+ inboundEvents["hass"] = "HASS_API";
33
+ inboundEvents["mqtt"] = "MQTT_API";
34
+ })(inboundEvents || (exports.inboundEvents = inboundEvents = {}));
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const logger_1 = require("./logger");
4
+ const socket_io_1 = require("socket.io");
5
+ const EventEmitter_1 = require("./EventEmitter");
6
+ const SocketEvents_1 = require("./SocketEvents");
7
+ const logger = (0, logger_1.module)('Socket');
8
+ /**
9
+ * The constructor
10
+ */
11
+ class SocketManager extends EventEmitter_1.TypedEventEmitter {
12
+ io;
13
+ activeSockets = new Map();
14
+ authMiddleware;
15
+ /**
16
+ * Binds socket.io to `server`
17
+ *
18
+ */
19
+ bindServer(server) {
20
+ this.io = new socket_io_1.Server(server, {
21
+ path: '/socket.io',
22
+ });
23
+ this.io.on('error', (err) => {
24
+ logger.error(`Socket error: ${err.message}`);
25
+ });
26
+ this.io
27
+ .use(this._authMiddleware())
28
+ .on('connection', this._onConnection.bind(this));
29
+ }
30
+ _authMiddleware() {
31
+ return (socket, next) => {
32
+ if (this.authMiddleware !== undefined) {
33
+ this.authMiddleware(socket, next);
34
+ }
35
+ else {
36
+ next();
37
+ }
38
+ };
39
+ }
40
+ /**
41
+ * Handles new socket connections
42
+ *
43
+ */
44
+ _onConnection(socket) {
45
+ logger.debug(`New connection ${socket.id}`);
46
+ // add socket to active sockets
47
+ this.activeSockets.set(socket.id, socket);
48
+ this.emit('clients', 'connection', this.activeSockets);
49
+ // register inbound events from this socket
50
+ for (const k in SocketEvents_1.inboundEvents) {
51
+ const eventName = SocketEvents_1.inboundEvents[k];
52
+ // pass socket reference as first parameter
53
+ socket.on(eventName, this._emitEvent.bind(this, eventName, socket));
54
+ }
55
+ // https://socket.io/docs/v4/server-socket-instance/#events
56
+ socket.on('disconnect', (reason) => {
57
+ logger.debug(`User disconnected from ${socket.id}: ${reason}`);
58
+ this.activeSockets.delete(socket.id);
59
+ this.emit('clients', 'disconnect', this.activeSockets);
60
+ });
61
+ }
62
+ /**
63
+ * Logs and emits the `eventName` with `socket` and `args` as parameters
64
+ *
65
+ */
66
+ _emitEvent(eventName, socket, data) {
67
+ logger.debug(`Event ${eventName} emitted to ${socket.id}`);
68
+ this.emit(eventName, socket, data);
69
+ }
70
+ }
71
+ exports.default = SocketManager;