iobroker.zigbee2mqtt 0.1.0 → 1.0.0

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/main.js CHANGED
@@ -7,31 +7,31 @@
7
7
  // The adapter-core module gives you access to the core ioBroker functions
8
8
  // you need to create an adapter
9
9
  const core = require('@iobroker/adapter-core');
10
- const WebSocket = require('ws');
11
- const defineDeviceFromExposes = require('./lib/exposes').defineDeviceFromExposes;
12
- const defineGroupDevice = require('./lib/groups').defineGroupDevice;
13
- const clearArray = require('./lib/utils').clearArray;
14
- let wsClient;
15
- let adapter;
16
- let createDevicesOrReady = false;
17
- const incStatsQueue = [];
18
- const createCache = {};
10
+ const NedbPersistence = require('aedes-persistence-nedb');
11
+ const mqtt = require('mqtt');
12
+ const checkConfig = require('./lib/check').checkConfig;
13
+ const adapterInfo = require('./lib/messages').adapterInfo;
14
+ const zigbee2mqttInfo = require('./lib/messages').zigbee2mqttInfo;
15
+ const Z2mController = require('./lib/z2mController').Z2mController;
16
+ const DeviceController = require('./lib/deviceController').DeviceController;
17
+ const StatesController = require('./lib/statesController').StatesController;
18
+
19
+
20
+ let mqttClient;
19
21
  // eslint-disable-next-line prefer-const
20
22
  let deviceCache = [];
21
23
  // eslint-disable-next-line prefer-const
22
24
  let groupCache = [];
23
- const lastSeenCache = {};
24
25
  let ping;
25
26
  let pingTimeout;
26
27
  let autoRestartTimeout;
27
- const wsHeartbeatIntervall = 5000;
28
- const restartTimeout = 1000;
29
- const deviceAvailableTimeout = 10 * 60; // 10 Minutes
30
- const batteryDeviceAvailableTimeout = 24 * 60 * 60; // 24 Hours
31
- const checkAvailableInterval = 30 * 1000; // 10 Seconds
32
- let debugLogEnabled;
33
- let proxyZ2MLogsEnabled;
34
28
  let checkAvailableTimout;
29
+ let debugDevices = '';
30
+ let logfilter = [];
31
+ let showInfo = true;
32
+ let statesController;
33
+ let deviceController;
34
+ let z2mController;
35
35
 
36
36
  class Zigbee2mqtt extends core.Adapter {
37
37
 
@@ -46,81 +46,52 @@ class Zigbee2mqtt extends core.Adapter {
46
46
  }
47
47
 
48
48
  async onReady() {
49
- // Initialize your adapter here
50
- adapter = this;
51
- this.log.info(`Zigbee2MQTT Frontend Server: ${this.config.server}`);
52
- this.log.info(`Zigbee2MQTT Frontend Port: ${this.config.port}`);
53
- this.log.info(`Zigbee2MQTT Debug Log: ${this.config.debugLogEnabled ? 'activated' : 'deactivated'}`);
54
- this.log.info(`Proxy Zigbee2MQTT Logs to ioBroker Logs: ${this.config.proxyZ2MLogs ? 'activated' : 'deactivated'}`);
55
49
 
56
- this.setStateAsync('info.connection', false, true);
57
- this.createWsClient(this.config.server, this.config.port);
58
50
 
59
- debugLogEnabled = this.config.debugLogEnabled;
60
- proxyZ2MLogsEnabled = this.config.proxyZ2MLogs;
61
- }
51
+ statesController = new StatesController(this, deviceCache, groupCache, debugDevices);
52
+ deviceController = new DeviceController(this, deviceCache, groupCache, this.config.useKelvin);
53
+ z2mController = new Z2mController(this, deviceCache, groupCache, logfilter);
62
54
 
63
- async createWsClient(server, port) {
64
- try {
65
- wsClient = new WebSocket(`ws://${server}:${port}/api`);
66
- wsClient.on('open', () => {
67
- this.logDebug('Websocket connectet');
68
- // Set connection state
69
- this.setState('info.connection', true, true);
70
- this.log.info('Connect to server over websocket connection.');
71
- // Send ping to server
72
- this.sendPingToServer();
73
- // Start Heartbeat
74
- this.wsHeartbeat();
75
- // Start CheckAvailableTimer
76
- this.checkAvailableTimer();
77
- });
78
- wsClient.on('pong', () => {
79
- //this.logDebug('Receive pong from server');
80
- this.wsHeartbeat();
81
- });
82
- // On Close
83
- wsClient.on('close', () => {
84
- this.setState('info.connection', false, true);
85
- this.log.warn('Websocket disconnectet');
86
- clearTimeout(ping);
87
- clearTimeout(pingTimeout);
55
+ // Initialize your adapter here
56
+ adapterInfo(this.config, this.log);
88
57
 
89
- if (wsClient.readyState === WebSocket.CLOSED) {
90
- this.autoRestart();
91
- }
92
- });
58
+ this.setStateAsync('info.connection', false, true);
93
59
 
94
- wsClient.on('message', (message) => { this.messageParse(message); });
95
- wsClient.on('error', (err) => { adapter.logDebug(err); });
96
- } catch (err) {
97
- this.logDebug(err);
60
+ const debugDevicesState = await this.getStateAsync('info.debugmessages');
61
+ if (debugDevicesState && debugDevicesState.val) {
62
+ debugDevices = String(debugDevicesState.val);
98
63
  }
99
- }
100
64
 
101
- async sendPingToServer() {
102
- //this.logDebug('Send ping to server');
103
- wsClient.ping();
104
- ping = setTimeout(() => {
105
- this.sendPingToServer();
106
- }, wsHeartbeatIntervall);
107
- }
65
+ const logfilterState = await this.getStateAsync('info.logfilter');
66
+ if (logfilterState && logfilterState.val) {
67
+ logfilter = String(logfilterState.val).split(';').filter(x => x); // filter removes empty strings here
68
+ }
108
69
 
109
- async wsHeartbeat() {
110
- clearTimeout(pingTimeout);
111
- pingTimeout = setTimeout(() => {
112
- this.logDebug('Websocked connection timed out');
113
- wsClient.terminate();
114
- clearTimeout(checkAvailableTimout);
115
- }, wsHeartbeatIntervall + 1000);
70
+ if (this.config.useExternalMqtt == true) {
71
+ mqttClient = mqtt.connect(`mqtt://${this.config.externalMqttServerIP}:${this.config.externalMqttServerPort}`, { clientId: `ioBroker.zigbee2mqtt_${Math.random().toString(16).slice(2, 8)}`, clean: true, reconnectPeriod: 500 });
72
+ } else {
73
+ const Aedes = require('aedes');
74
+ const net = require('net');
75
+ const db = new NedbPersistence({
76
+ path: `${core.getAbsoluteInstanceDataDir(this)}/mqttData`,
77
+ prefix: ''
78
+ });
79
+ // @ts-ignore
80
+ const aedes = Aedes({ persistence: db });
81
+ const mqttServer = net.createServer(aedes.handle);
82
+ mqttServer.listen(this.config.mqttServerPort, this.config.mqttServerIPBind, () => { });
83
+ mqttClient = mqtt.connect(`mqtt://${this.config.mqttServerIPBind}:${this.config.mqttServerPort}`, { clientId: 'ioBroker.zigbee2mqtt', clean: true, reconnectPeriod: 500 });
84
+ }
85
+
86
+ mqttClient.on('connect', () => { this.setStateAsync('info.connection', true, true); });
87
+ mqttClient.subscribe('#');
88
+ mqttClient.on('message', (topic, payload) => {
89
+ const newMessage = `{"payload":${payload.toString() == '' ? '"null"' : payload.toString()},"topic":"${topic.slice(topic.search('/') + 1)}"}`;
90
+ console.log(newMessage);
91
+ this.messageParse(newMessage);
92
+ });
116
93
  }
117
94
 
118
- async autoRestart() {
119
- this.log.warn(`Start try again in ${restartTimeout / 1000} seconds...`);
120
- autoRestartTimeout = setTimeout(() => {
121
- this.onReady();
122
- }, restartTimeout);
123
- }
124
95
 
125
96
  async messageParse(message) {
126
97
  const messageObj = JSON.parse(message);
@@ -129,34 +100,41 @@ class Zigbee2mqtt extends core.Adapter {
129
100
  case 'bridge/config':
130
101
  break;
131
102
  case 'bridge/info':
103
+ if (showInfo) {
104
+ zigbee2mqttInfo(messageObj.payload, this.log);
105
+ checkConfig(messageObj.payload.config, this.log);
106
+ showInfo = false;
107
+ }
132
108
  break;
133
109
  case 'bridge/state':
134
110
  break;
135
111
  case 'bridge/devices':
136
- // As long as we are busy creating the devices, the states are written to the queue.
137
- createDevicesOrReady = false;
138
- await this.createDeviceDefinitions(deviceCache, messageObj.payload);
139
- await this.createOrUpdateDevices(deviceCache);
140
- createDevicesOrReady = true;
141
-
142
- // Now process all entries in the states queue
143
- while (incStatsQueue.length > 0) {
144
- this.processDeviceMessage(incStatsQueue.shift());
145
- }
112
+ await deviceController.createDeviceDefinitions(messageObj.payload);
113
+ await deviceController.createOrUpdateDevices();
114
+ await statesController.subscribeWritableStates();
115
+ statesController.processQueue();
146
116
  break;
147
117
  case 'bridge/groups':
148
- await this.createGroupDefinitions(groupCache, messageObj.payload);
149
- await this.createOrUpdateDevices(groupCache);
118
+ await deviceController.createGroupDefinitions(messageObj.payload);
119
+ await deviceController.createOrUpdateDevices();
120
+ await statesController.subscribeWritableStates();
121
+ statesController.processQueue();
150
122
  break;
151
123
  case 'bridge/event':
124
+ deviceController.processRemoveEvent(messageObj);
152
125
  break;
153
126
  case 'bridge/extensions':
154
127
  break;
155
128
  case 'bridge/logging':
156
- if (proxyZ2MLogsEnabled == true) {
157
- this.proxyZ2MLogs(messageObj);
129
+ if (this.config.proxyZ2MLogs == true) {
130
+ z2mController.proxyZ2MLogs(messageObj);
158
131
  }
159
132
  break;
133
+ case 'bridge/response/device/rename':
134
+ await deviceController.renameDeviceInCache(messageObj);
135
+ await deviceController.createOrUpdateDevices();
136
+ statesController.processQueue();
137
+ break;
160
138
  case 'bridge/response/networkmap':
161
139
  break;
162
140
  case 'bridge/response/touchlink/scan':
@@ -166,314 +144,36 @@ class Zigbee2mqtt extends core.Adapter {
166
144
  case 'bridge/response/touchlink/factory_reset':
167
145
  break;
168
146
  default:
169
- // States
170
147
  {
171
- if (!messageObj.topic.includes('/')) {
172
- // As long as we are busy creating the devices, the states are written to the queue.
173
- if (createDevicesOrReady == false) {
174
- incStatsQueue[incStatsQueue.length] = messageObj;
148
+ // {"payload":{"state":"online"},"topic":"FL.Licht.Links/availability"} ----> {"payload":{"available":true},"topic":"FL.Licht.Links"}
149
+ if (messageObj.topic.endsWith('/availability')) {
150
+ const topicSplit = messageObj.topic.split('/');
151
+
152
+ // If an availability message for an old device ID comes with a payload of NULL, this is the indicator that a device has been unnamed.
153
+ // If this is then still available in the cache, the messages must first be cached.
154
+ if (messageObj.payload == 'null') {
175
155
  break;
176
156
  }
177
- this.processDeviceMessage(messageObj);
178
- }
179
- }
180
- break;
181
- }
182
- }
183
-
184
- async processDeviceMessage(messageObj) {
185
- this.logDebug(`processDeviceMessage -> messageObj: ${JSON.stringify(messageObj)}`);
186
- // Is payload present?
187
- if (messageObj.payload == '') {
188
- return;
189
- }
190
-
191
- const device = deviceCache.find(x => x.id == messageObj.topic);
192
- if (device) {
193
- this.logDebug(`processDeviceMessage -> device: ${JSON.stringify(device)}`);
194
- try {
195
- // The state available must not be considered for the cacheLastSeen
196
- // Groups must not be considered for the cacheLastSeen
197
- if (messageObj.payload.available == undefined && !device.ieee_address.startsWith('group_')) {
198
- await this.cacheLastSeen(device, messageObj);
199
- }
200
- this.setDeviceState(messageObj, device);
201
- this.checkAvailable(device.ieee_address);
202
-
203
- } catch (error) {
204
- adapter.log.error(error);
205
- }
206
- }
207
- else {
208
- adapter.log.warn(`Device: ${messageObj.topic} not found`);
209
- }
210
- }
211
-
212
- async cacheLastSeen(device, messageObj) {
213
- this.logDebug(`cacheLastSeen -> device: ${JSON.stringify(device)}`);
214
- this.logDebug(`cacheLastSeen -> messageObj: ${JSON.stringify(messageObj)}`);
215
- if (messageObj.payload.last_seen) {
216
- lastSeenCache[device.ieee_address] = new Date(messageObj.payload.last_seen).getTime();
217
- } else {
218
- lastSeenCache[device.ieee_address] = new Date().getTime();
219
- }
220
- this.logDebug(`cacheLastSeen -> deviceLastSeenCache: ${JSON.stringify(lastSeenCache)}`);
221
- }
222
-
223
- async checkAvailableTimer() {
224
- checkAvailableTimout = setTimeout(async () => {
225
- await this.checkAvailable(null);
226
- this.checkAvailableTimer();
227
- }, checkAvailableInterval);
228
- }
229
-
230
- async checkAvailable(ieee_address) {
231
- this.logDebug(`checkAvailable -> ieee_address: ${ieee_address}`);
232
- let checkList = {};
233
- if (ieee_address) {
234
- checkList[ieee_address] = null;
235
- }
236
- else {
237
- checkList = lastSeenCache;
238
- }
239
-
240
- for (const ieee_address in checkList) {
241
- const device = deviceCache.find(x => x.ieee_address == ieee_address);
242
-
243
- if (!device) {
244
- continue;
245
- }
246
-
247
- const isBatteryDevice = device.power_source == 'Battery' ? true : false;
248
- const offlineTimeout = isBatteryDevice ? batteryDeviceAvailableTimeout : deviceAvailableTimeout;
249
- const diffSec = Math.round((new Date().getTime() - lastSeenCache[ieee_address]) / 1000);
250
- const available = diffSec < offlineTimeout;
251
-
252
- this.logDebug(`checkAvailable -> device.id: ${device.id}, available: ${available}, diffSec: ${diffSec}, isBatteryDevice: ${isBatteryDevice}`);
253
-
254
- if (device.available == null || device.available != available) {
255
- this.logDebug(`checkAvailable -> device.id: ${device.id}, available: ${available}, diffSec: ${diffSec}, isBatteryDevice: ${isBatteryDevice}`);
256
- device.available = available;
257
- const messageObj = {
258
- topic: device.id,
259
- payload: {
260
- available: available,
261
- }
262
- };
263
-
264
- this.processDeviceMessage(messageObj);
265
- }
266
- }
267
- }
268
-
269
- async setDeviceState(messageObj, device) {
270
-
271
- for (const [key, value] of Object.entries(messageObj.payload)) {
272
- this.logDebug(`setDeviceState -> key: ${key}`);
273
- this.logDebug(`setDeviceState -> value: ${JSON.stringify(value)}`);
274
-
275
- let states;
276
- if (key == 'action') {
277
- states = device.states.filter(x => (x.prop && x.prop == key) && x.id == value);
278
- } else {
279
- states = device.states.filter(x => (x.prop && x.prop == key) || x.id == key);
280
- }
281
- this.logDebug(`setDeviceState -> states: ${JSON.stringify(states)}`);
282
-
283
- for (const state of states) {
284
- if (!state) {
285
- continue;
286
- }
287
- const stateName = `${device.ieee_address}.${state.id}`;
288
-
289
- if (state.getter) {
290
- this.setState(stateName, state.getter(messageObj.payload), true);
291
- }
292
- else {
293
- this.setState(stateName, value, true);
294
- }
295
- }
296
- }
297
- }
298
-
299
- async createDeviceDefinitions(cache, exposes) {
300
- clearArray(cache);
301
- for (const expose of exposes) {
302
- if (expose.definition != null) {
303
- await defineDeviceFromExposes(cache, expose.friendly_name, expose.ieee_address, expose.definition, expose.power_source);
304
- }
305
- }
306
- }
307
157
 
308
- async createGroupDefinitions(cache, exposes) {
309
- clearArray(cache);
310
- for (const expose of exposes) {
311
- await defineGroupDevice(cache, expose.friendly_name, `group_${expose.id}`, expose.scenes);
312
- }
313
- }
314
-
315
- async createOrUpdateDevices(cache) {
316
- for (const device of cache) {
317
- const deviceName = device.id == device.ieee_address ? '' : device.id;
318
- if (!createCache[device.ieee_address] || createCache[device.ieee_address].common.name != deviceName) {
319
- const deviceObj = {
320
- type: 'device',
321
- common: {
322
- name: deviceName,
323
- statusStates: {
324
- onlineId: `${this.name}.${this.instance}.${device.ieee_address}.available`
325
- },
326
- },
327
-
328
- native: {}
329
- };
330
- //@ts-ignore
331
- await this.extendObjectAsync(device.ieee_address, deviceObj);
332
- createCache[device.ieee_address] = deviceObj;
333
- }
334
-
335
- // Special handling for groups, here it is checked whether the scenes match the current data from z2m.
336
- // If necessary, scenes are automatically deleted from ioBroker.
337
- if (device.ieee_address.startsWith('group_')) {
338
- const sceneStates = await this.getStatesAsync(`${device.ieee_address}.scene_*`);
339
- const sceneIDs = Object.keys(sceneStates);
340
- for (const sceneID of sceneIDs) {
341
- const stateID = sceneID.split('.')[3];
342
- if (device.states.find(x => x.id == stateID) == null) {
343
- this.delObject(sceneID);
158
+ if (topicSplit.length == 2 && messageObj.payload && messageObj.payload.state) {
159
+ const newMessage = {
160
+ payload: { available: messageObj.payload.state == 'online' },
161
+ topic: topicSplit[0]
162
+ };
163
+ statesController.processDeviceMessage(newMessage);
164
+ }
165
+ // States
166
+ } else if (!messageObj.topic.includes('/')) {
167
+ statesController.processDeviceMessage(messageObj);
344
168
  }
345
169
  }
346
- }
347
-
348
- for (const state of device.states) {
349
- if (!createCache[device.ieee_address][state.id] || createCache[device.ieee_address][state.id].name != state.name) {
350
- const iobState = await this.copyAndCleanStateObj(state);
351
- this.logDebug(`Orig. state: ${JSON.stringify(state)}`);
352
- this.logDebug(`Cleaned. state: ${JSON.stringify(iobState)}`);
353
-
354
-
355
-
356
- await this.extendObjectAsync(`${device.ieee_address}.${state.id}`, {
357
- type: 'state',
358
- common: iobState,
359
- native: {},
360
- });
361
- createCache[device.ieee_address][state.id] = state.name;
362
- }
363
- }
364
- }
365
- this.subscribeWritableStates();
366
- }
367
-
368
- async copyAndCleanStateObj(state) {
369
- const iobState = { ...state };
370
- const blacklistedKeys = [
371
- 'setter',
372
- 'setterOpt',
373
- 'getter',
374
- 'setattr',
375
- 'readable',
376
- 'writable',
377
- 'isOption',
378
- 'inOptions'
379
- ];
380
- for (const blacklistedKey of blacklistedKeys) {
381
- delete iobState[blacklistedKey];
382
- }
383
- return iobState;
384
- }
385
-
386
- async subscribeWritableStates() {
387
- await this.unsubscribeObjectsAsync('*');
388
- for (const device of deviceCache) {
389
- for (const state of device.states) {
390
- if (state.write == true) {
391
- this.subscribeStatesAsync(`${device.ieee_address}.${state.id}`);
392
- }
393
- }
394
- }
395
- }
396
-
397
- async createZ2MMessage(id, state) {
398
-
399
- const splitedID = id.split('.');
400
-
401
- if (splitedID.length < 4) {
402
- this.log.warn(`state ${id} not valid`);
403
- return;
404
- }
405
-
406
- const ieee_address = splitedID[2];
407
- const stateName = splitedID[3];
408
-
409
- const device = deviceCache.find(d => d.ieee_address == ieee_address);
410
-
411
- if (!device) {
412
- return;
413
- }
414
-
415
- const deviceState = device.states.find(s => s.id == stateName);
416
-
417
- if (!deviceState) {
418
- return;
419
- }
420
-
421
- let stateVal = state.val;
422
- if (deviceState.setter) {
423
- stateVal = deviceState.setter(state.val);
424
- }
425
-
426
-
427
- let stateID = deviceState.id;
428
- if (deviceState.prop) {
429
- stateID = deviceState.prop;
430
- }
431
-
432
- let topic = `${device.ieee_address}/set`;
433
- if (device.ieee_address.includes('group_')) {
434
- topic = `${device.id}/set`;
435
- }
436
-
437
- const controlObj = {
438
- payload: {
439
- [stateID]: stateVal
440
- },
441
- topic: topic
442
- };
443
- // set stats with role 'button' always immediately to ack = true, because these are not reported back by Zigbee2MQTT
444
- if (deviceState.role == 'button') {
445
- this.setState(id, state, true);
446
- }
447
-
448
- return JSON.stringify(controlObj);
449
- }
450
-
451
- async proxyZ2MLogs(messageObj) {
452
- this.logDebug(`proxyZ2MLogs -> messageObj: ${JSON.stringify(messageObj)}`);
453
-
454
- const logLevel = messageObj.payload.level;
455
- const logMessage = messageObj.payload.message;
456
-
457
- switch (logLevel) {
458
- case 'debug':
459
- case 'info':
460
- case 'error':
461
- this.log[logLevel](logMessage);
462
170
  break;
463
- case 'warning':
464
- this.log.warn(logMessage);
465
- break;
466
- }
467
- }
468
-
469
- async logDebug(message) {
470
- if (debugLogEnabled == true) {
471
- this.log.debug(message);
472
171
  }
473
172
  }
474
173
 
475
- onUnload(callback) {
174
+ async onUnload(callback) {
476
175
  try {
176
+ await statesController.setAllAvailableToFalse();
477
177
  clearTimeout(ping);
478
178
  clearTimeout(pingTimeout);
479
179
  clearTimeout(autoRestartTimeout);
@@ -486,12 +186,24 @@ class Zigbee2mqtt extends core.Adapter {
486
186
 
487
187
  async onStateChange(id, state) {
488
188
  if (state && state.ack == false) {
489
- const message = await this.createZ2MMessage(id, state);
490
- wsClient.send(message);
189
+ if (id.includes('info.debugmessages')) {
190
+ debugDevices = state.val;
191
+ this.setState(id, state.val, true);
192
+ return;
193
+ }
194
+ if (id.includes('info.logfilter')) {
195
+ logfilter = state.val.split(';').filter(x => x); // filter removes empty strings here
196
+ this.setState(id, state.val, true);
197
+ return;
198
+ }
199
+
200
+ const message = await z2mController.createZ2MMessage(id, state) || { topic: '', payload: '' };
201
+ mqttClient.publish('zigbee2mqtt/' + message.topic, JSON.stringify(message.payload));
491
202
  }
492
203
  }
493
204
  }
494
205
 
206
+
495
207
  if (require.main !== module) {
496
208
  // Export the constructor in compact mode
497
209
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee2mqtt",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Zigbee2MQTT adapter for ioBroker",
5
5
  "author": {
6
6
  "name": "Dennis Rathjen",
@@ -21,7 +21,11 @@
21
21
  "dependencies": {
22
22
  "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
23
23
  "@alcalzone/release-script-plugin-license": "^3.5.9",
24
- "@iobroker/adapter-core": "^2.6.6",
24
+ "@iobroker/adapter-core": "^2.6.7",
25
+ "aedes": "^0.48.0",
26
+ "aedes-persistence-nedb": "^2.0.3",
27
+ "mqtt": "^4.3.7",
28
+ "net": "^1.0.2",
25
29
  "ws": "^8.9.0"
26
30
  },
27
31
  "devDependencies": {
@@ -32,19 +36,19 @@
32
36
  "@types/chai": "^4.3.3",
33
37
  "@types/chai-as-promised": "^7.1.5",
34
38
  "@types/mocha": "^10.0.0",
35
- "@types/node": "^18.7.23",
39
+ "@types/node": "^18.8.3",
36
40
  "@types/proxyquire": "^1.3.28",
37
41
  "@types/sinon": "^10.0.13",
38
42
  "@types/sinon-chai": "^3.2.8",
39
43
  "chai": "^4.3.6",
40
44
  "chai-as-promised": "^7.1.1",
41
- "eslint": "^8.24.0",
45
+ "eslint": "^8.25.0",
42
46
  "eslint-config-prettier": "^8.5.0",
43
47
  "eslint-plugin-prettier": "^4.2.1",
44
48
  "mocha": "^10.0.0",
45
49
  "prettier": "^2.7.1",
46
50
  "proxyquire": "^2.1.3",
47
- "sinon": "^14.0.0",
51
+ "sinon": "^14.0.1",
48
52
  "sinon-chai": "^3.7.0",
49
53
  "typescript": "~4.8.4"
50
54
  },
package/lib/groups.js DELETED
@@ -1,45 +0,0 @@
1
- const states = require('./states').states;
2
- const utils = require('./utils');
3
-
4
- function defineGroupDevice(devices, groupID, ieee_address, scenes) {
5
- const newDevice = {
6
- id: groupID,
7
- ieee_address: ieee_address,
8
- icon: undefined,
9
- states: [
10
- states.state,
11
- states.brightness,
12
- states.colortemp,
13
- states.color,
14
- states.brightness_move,
15
- states.colortemp_move,
16
- states.transition_time,
17
- //states.brightness_step
18
- ],
19
- };
20
-
21
- // Create buttons for scenes
22
- for (const scene of scenes) {
23
- const sceneSate = {
24
- id: `scene_${scene.id}`,
25
- prop: `scene_recall`,
26
- name: scene.name,
27
- icon: undefined,
28
- role: 'button',
29
- write: true,
30
- read: true,
31
- type: 'boolean',
32
- setter: (value) => (value) ? scene.id : undefined
33
- };
34
- // @ts-ignore
35
- newDevice.states.push(sceneSate);
36
- }
37
-
38
- // if the device is already present in the cache, remove it
39
- utils.removeDeviceByIeee(devices, ieee_address);
40
- devices.push(newDevice);
41
- }
42
-
43
- module.exports = {
44
- defineGroupDevice: defineGroupDevice,
45
- };