homebridge-deconz 0.0.6 → 0.0.11
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/README.md +8 -0
- package/cli/deconz.js +980 -0
- package/config.schema.json +1 -1
- package/lib/Client/ApiError.js +42 -0
- package/lib/{DeconzClient.js → Deconz/ApiClient.js} +82 -158
- package/lib/Deconz/ApiError.js +42 -0
- package/lib/Deconz/ApiResponse.js +54 -0
- package/lib/Deconz/Device.js +100 -0
- package/lib/{DeconzDiscovery.js → Deconz/Discovery.js} +4 -3
- package/lib/Deconz/Resource.js +1206 -0
- package/lib/{DeconzWsClient.js → Deconz/WsClient.js} +59 -44
- package/lib/Deconz/index.js +21 -0
- package/lib/DeconzAccessory/Contact.js +54 -0
- package/lib/DeconzAccessory/Gateway.js +316 -374
- package/lib/DeconzAccessory/Light.js +72 -0
- package/lib/DeconzAccessory/Motion.js +51 -0
- package/lib/DeconzAccessory/Sensor.js +35 -0
- package/lib/DeconzAccessory/Temperature.js +63 -0
- package/lib/DeconzAccessory/Thermostat.js +50 -0
- package/lib/DeconzAccessory/WarningDevice.js +56 -0
- package/lib/DeconzAccessory/WindowCovering.js +47 -0
- package/lib/DeconzAccessory/index.js +216 -0
- package/lib/DeconzPlatform.js +8 -3
- package/lib/DeconzService/AirPressure.js +43 -0
- package/lib/DeconzService/AirQuality.js +20 -10
- package/lib/DeconzService/Alarm.js +16 -9
- package/lib/DeconzService/Battery.js +43 -0
- package/lib/DeconzService/Button.js +12 -2
- package/lib/DeconzService/CarbonMonoxide.js +38 -0
- package/lib/DeconzService/Consumption.js +65 -0
- package/lib/DeconzService/Contact.js +60 -0
- package/lib/DeconzService/Daylight.js +132 -0
- package/lib/DeconzService/DeviceSettings.js +13 -5
- package/lib/DeconzService/Flag.js +52 -0
- package/lib/DeconzService/GatewaySettings.js +8 -58
- package/lib/DeconzService/Humidity.js +37 -0
- package/lib/DeconzService/Leak.js +38 -0
- package/lib/DeconzService/Light.js +376 -0
- package/lib/DeconzService/LightLevel.js +54 -0
- package/lib/DeconzService/LightsResource.js +112 -0
- package/lib/DeconzService/Motion.js +101 -0
- package/lib/DeconzService/Outlet.js +76 -0
- package/lib/DeconzService/Power.js +83 -0
- package/lib/DeconzService/SensorsResource.js +96 -0
- package/lib/DeconzService/Smoke.js +38 -0
- package/lib/DeconzService/Status.js +53 -0
- package/lib/DeconzService/Switch.js +93 -0
- package/lib/DeconzService/Temperature.js +63 -0
- package/lib/DeconzService/Thermostat.js +175 -0
- package/lib/DeconzService/WarningDevice.js +68 -0
- package/lib/DeconzService/WindowCovering.js +139 -0
- package/lib/DeconzService/index.js +94 -0
- package/package.json +7 -4
- package/lib/DeconzAccessory/Device.js +0 -91
- package/lib/DeconzAccessory.js +0 -16
- package/lib/DeconzDevice.js +0 -245
- package/lib/DeconzService/Sensor.js +0 -58
- package/lib/DeconzService.js +0 -43
@@ -6,17 +6,11 @@
|
|
6
6
|
'use strict'
|
7
7
|
|
8
8
|
const homebridgeLib = require('homebridge-lib')
|
9
|
-
const util = require('util')
|
10
9
|
|
11
|
-
const
|
12
|
-
const DeconzWsClient = require('../DeconzWsClient')
|
13
|
-
const DeconzDevice = require('../DeconzDevice')
|
10
|
+
const Deconz = require('../Deconz')
|
14
11
|
const DeconzAccessory = require('../DeconzAccessory')
|
15
12
|
const DeconzService = require('../DeconzService')
|
16
13
|
|
17
|
-
const { toInt, toObject, toString } = homebridgeLib.OptionParser
|
18
|
-
const { parseUniqueid } = DeconzClient
|
19
|
-
|
20
14
|
const rtypes = ['lights', 'sensors', 'groups']
|
21
15
|
|
22
16
|
const periodicEvents = [
|
@@ -26,7 +20,6 @@ const periodicEvents = [
|
|
26
20
|
]
|
27
21
|
|
28
22
|
/** Delegate class for a deCONZ gateway.
|
29
|
-
* @class
|
30
23
|
* @extends AccessoryDelegate
|
31
24
|
* @memberof DeconzAccessory
|
32
25
|
*/
|
@@ -46,7 +39,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
46
39
|
model: params.config.modelid + ' / ' + params.config.devicename,
|
47
40
|
firmware: '0.0.0',
|
48
41
|
software: params.config.swversion,
|
49
|
-
category: platform.Accessory.Categories.
|
42
|
+
category: platform.Accessory.Categories.BRIDGE
|
50
43
|
})
|
51
44
|
|
52
45
|
this.gateway = this
|
@@ -60,31 +53,75 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
60
53
|
* devices.
|
61
54
|
* @property {Object} fullState - The gateway's full state, from the
|
62
55
|
* last time the gateway was polled.
|
63
|
-
* @property {string} host - Gateway hostname or IP address and port.
|
64
56
|
*/
|
65
57
|
this.context // eslint-disable-line no-unused-expressions
|
66
|
-
|
67
58
|
this.context.host = params.host
|
68
59
|
this.context.config = params.config
|
69
60
|
if (this.context.blacklist == null) {
|
70
61
|
this.context.blacklist = {}
|
71
62
|
}
|
63
|
+
if (this.context.fullState != null) {
|
64
|
+
this.analyseFullState(this.context.fullState, { analyseOnly: true })
|
65
|
+
}
|
66
|
+
|
67
|
+
this.addPropertyDelegate({
|
68
|
+
key: 'apiKey',
|
69
|
+
silent: true
|
70
|
+
}).on('didSet', (value) => {
|
71
|
+
this.client.apiKey = value
|
72
|
+
})
|
73
|
+
|
74
|
+
this.addPropertyDelegate({
|
75
|
+
key: 'host',
|
76
|
+
value: params.host,
|
77
|
+
silent: true
|
78
|
+
}).on('didSet', (value) => {
|
79
|
+
if (this.client != null) {
|
80
|
+
this.client.host = value
|
81
|
+
}
|
82
|
+
if (this.wsClient != null) {
|
83
|
+
this.wsClient.host = this.values.host.split(':')[0] +
|
84
|
+
':' + this.values.wsPort
|
85
|
+
}
|
86
|
+
})
|
87
|
+
this.values.host = params.host
|
88
|
+
|
89
|
+
this.addPropertyDelegate({
|
90
|
+
key: 'rtypes',
|
91
|
+
value: [],
|
92
|
+
silent: true
|
93
|
+
}).on('didSet', async () => {
|
94
|
+
this.pollNext = true
|
95
|
+
})
|
96
|
+
|
97
|
+
this.addPropertyDelegate({
|
98
|
+
key: 'wsPort',
|
99
|
+
value: 443,
|
100
|
+
silent: true
|
101
|
+
}).on('didSet', (value) => {
|
102
|
+
if (this.wsClient != null) {
|
103
|
+
this.wsClient.host = this.values.host.split(':')[0] +
|
104
|
+
':' + this.values.wsPort
|
105
|
+
}
|
106
|
+
})
|
72
107
|
|
73
108
|
this.log(
|
74
109
|
'%s %s gateway v%s', this.values.manufacturer, this.values.model,
|
75
110
|
this.values.software
|
76
111
|
)
|
77
112
|
|
78
|
-
/** Map of Accessory delegates by id for the
|
113
|
+
/** Map of Accessory delegates by id for the gateway.
|
79
114
|
* @type {Object<string, DeconzAccessory.Device>}
|
80
115
|
*/
|
81
116
|
this.accessoryById = {}
|
82
117
|
|
83
|
-
/** Map of Accessory delegates by rpath for the
|
118
|
+
/** Map of Accessory delegates by rpath for the gateway.
|
84
119
|
* @type {Object<string, DeconzAccessory.Device>}
|
85
120
|
*/
|
86
121
|
this.accessoryByRpath = {}
|
87
122
|
|
123
|
+
this.defaultTransitionTime = 0.4
|
124
|
+
|
88
125
|
/** Map of errors by device ID trying to expose the corresponding accessory.
|
89
126
|
* @type {Object<string, Error>}
|
90
127
|
*/
|
@@ -95,11 +132,6 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
95
132
|
*/
|
96
133
|
this.serviceById = {}
|
97
134
|
|
98
|
-
/** Map of unsupported devices.
|
99
|
-
* @type {Object.<string, boolean>}
|
100
|
-
*/
|
101
|
-
this.unsupported = {}
|
102
|
-
|
103
135
|
/** The service delegate for the Gateway Settings settings.
|
104
136
|
* @type {DeconzService.GatewaySettings}
|
105
137
|
*/
|
@@ -108,6 +140,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
108
140
|
primaryService: true,
|
109
141
|
host: params.host
|
110
142
|
})
|
143
|
+
this.manageLogLevel(this.service.characteristicDelegate('logLevel'))
|
111
144
|
|
112
145
|
/** The service delegate for the Stateless Programmable Switch service.
|
113
146
|
* @type {DeconzService.Button}
|
@@ -129,6 +162,18 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
129
162
|
.on('shutdown', this.shutdown)
|
130
163
|
}
|
131
164
|
|
165
|
+
get transitionTime () { return this.service.values.transitionTime }
|
166
|
+
|
167
|
+
async resetTransitionTime () {
|
168
|
+
if (this.resetting) {
|
169
|
+
return
|
170
|
+
}
|
171
|
+
this.resetting = true
|
172
|
+
await homebridgeLib.timeout(this.platform.config.waitTimeUpdate)
|
173
|
+
this.service.values.transitionTime = this.defaultTransitionTime
|
174
|
+
this.resetting = false
|
175
|
+
}
|
176
|
+
|
132
177
|
/** Log debug messages.
|
133
178
|
*/
|
134
179
|
identify () {
|
@@ -156,7 +201,8 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
156
201
|
)
|
157
202
|
const exposeErrors = Object.keys(this.exposeErrorById).sort()
|
158
203
|
this.vdebug(
|
159
|
-
'%d accessories with expose errors', exposeErrors.length,
|
204
|
+
'%d accessories with expose errors: %j', exposeErrors.length,
|
205
|
+
exposeErrors
|
160
206
|
)
|
161
207
|
const blacklist = Object.keys(this.context.blacklist).sort()
|
162
208
|
this.vdebug(
|
@@ -170,9 +216,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
170
216
|
try {
|
171
217
|
this.debug('initialising...')
|
172
218
|
this.initialBeat = beat
|
173
|
-
if (this.context.fullState != null) {
|
174
|
-
|
175
|
-
|
219
|
+
// if (this.context.fullState != null) {
|
220
|
+
// this.analyseFullState(this.context.fullState, { logUnsupported: true })
|
221
|
+
// for (const id of this.restoredAccessories) {
|
222
|
+
// try {
|
223
|
+
// this.addAccessory(id)
|
224
|
+
// } catch (error) { this.error(error) }
|
225
|
+
// }
|
226
|
+
// }
|
176
227
|
await this.connect()
|
177
228
|
this.initialised = true
|
178
229
|
this.debug('initialised')
|
@@ -186,7 +237,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
186
237
|
* GET `/config` (from {@link DeconzDiscovery#config config()}.
|
187
238
|
*/
|
188
239
|
found (host, config) {
|
189
|
-
this.
|
240
|
+
this.values.host = host
|
190
241
|
this.context.config = config
|
191
242
|
this.values.software = config.swversion
|
192
243
|
}
|
@@ -208,10 +259,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
208
259
|
}
|
209
260
|
}
|
210
261
|
}
|
211
|
-
if (beat - this.pollBeat >= this.service.values.heartrate) {
|
212
|
-
this.pollNext = true
|
213
|
-
}
|
214
|
-
if (this.pollNext) {
|
262
|
+
if (beat - this.pollBeat >= this.service.values.heartrate || this.pollNext) {
|
215
263
|
this.pollBeat = beat
|
216
264
|
await this.poll()
|
217
265
|
}
|
@@ -221,11 +269,12 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
221
269
|
update (config) {
|
222
270
|
this.values.software = config.swversion
|
223
271
|
this.values.firmware = config.fwversion
|
272
|
+
this.values.wsPort = config.websocketport
|
224
273
|
this.service.update(config)
|
225
274
|
if (this.checkApiKeys) {
|
226
|
-
const myEntry = config.whitelist[this.
|
275
|
+
const myEntry = config.whitelist[this.values.apiKey]
|
227
276
|
for (const key in config.whitelist) {
|
228
|
-
if (key !== this.
|
277
|
+
if (key !== this.values.apiKey) {
|
229
278
|
const entry = config.whitelist[key]
|
230
279
|
if (entry.name === myEntry.name) {
|
231
280
|
this.warn('%s: potentially stale api key: %j', key, entry)
|
@@ -242,10 +291,10 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
242
291
|
/** REST API client for the gateway.
|
243
292
|
* @type {DeconzClient}
|
244
293
|
*/
|
245
|
-
this.client = new
|
246
|
-
|
294
|
+
this.client = new Deconz.ApiClient({
|
295
|
+
apiKey: this.values.apiKey,
|
247
296
|
config: this.context.config,
|
248
|
-
|
297
|
+
host: this.values.host,
|
249
298
|
maxSockets: this.platform.config.parallelRequests,
|
250
299
|
timeout: this.platform.config.timeout,
|
251
300
|
waitTimePut: this.platform.config.waitTimePut,
|
@@ -298,8 +347,8 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
298
347
|
/** Client for gateway web socket notifications.
|
299
348
|
* @type {DeconzWsClient}
|
300
349
|
*/
|
301
|
-
this.wsClient = new
|
302
|
-
host: this.
|
350
|
+
this.wsClient = new Deconz.WsClient({
|
351
|
+
host: this.values.host.split(':')[0] + ':' + this.values.wsPort,
|
303
352
|
retryTime: 15
|
304
353
|
})
|
305
354
|
this.wsClient
|
@@ -309,19 +358,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
309
358
|
.on('listening', (url) => {
|
310
359
|
this.log('websocket connected to %s', url)
|
311
360
|
})
|
312
|
-
.on('changed', (
|
313
|
-
this.vdebug('%s: event: %j', rpath, obj)
|
361
|
+
.on('changed', (rtype, rid, body) => {
|
314
362
|
try {
|
315
|
-
const
|
316
|
-
|
363
|
+
const rpath = '/' + rtype + '/' + rid
|
364
|
+
this.vdebug('%s: changed: %j', rpath, body)
|
317
365
|
const accessory = this.accessoryByRpath[rpath]
|
318
366
|
if (accessory != null) {
|
319
|
-
|
320
|
-
|
321
|
-
body = {}
|
322
|
-
body[a[3]] = obj
|
323
|
-
}
|
324
|
-
/** Emitted when resource has been polled.
|
367
|
+
/** Emitted when a change notificatoin for a resource has been
|
368
|
+
* received over the web socket.
|
325
369
|
* @event DeconzAccessory.Device#changed
|
326
370
|
* @param {string} rpath - The resource path.
|
327
371
|
* @param {Object} body - The resource body.
|
@@ -332,6 +376,18 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
332
376
|
this.warn('websocket error: %s', error)
|
333
377
|
}
|
334
378
|
})
|
379
|
+
.on('added', (rtype, rid, body) => {
|
380
|
+
this.vdebug('/%s/%d: added: %j', rtype, rid, body)
|
381
|
+
if (this.service.values[rtype]) {
|
382
|
+
this.pollNext = true
|
383
|
+
}
|
384
|
+
})
|
385
|
+
.on('deleted', (rtype, rid) => {
|
386
|
+
this.vdebug('/%s/%d: deleted', rtype, rid)
|
387
|
+
if (this.service.values[rtype]) {
|
388
|
+
this.pollNext = true
|
389
|
+
}
|
390
|
+
})
|
335
391
|
.on('closed', (url, retryTime) => {
|
336
392
|
if (retryTime > 0) {
|
337
393
|
this.log(
|
@@ -351,24 +407,24 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
351
407
|
*/
|
352
408
|
async connect (retry = 0) {
|
353
409
|
if (!this.service.values.expose) {
|
354
|
-
this.warn('unlock
|
410
|
+
this.warn('unlock gateway and set Expose to obtain an API key')
|
355
411
|
return
|
356
412
|
}
|
357
413
|
try {
|
358
|
-
if (this.
|
359
|
-
this.
|
360
|
-
await this.client.
|
414
|
+
if (this.values.apiKey == null) {
|
415
|
+
this.values.apiKey =
|
416
|
+
await this.client.getApiKey('homebridge-deconz')
|
361
417
|
}
|
362
418
|
this.wsClient.listen()
|
363
419
|
this.checkApiKeys = true
|
364
420
|
for (const id in this.exposeErrorById) {
|
365
421
|
this.resetExposeError(id)
|
366
422
|
}
|
423
|
+
this.context.fullState = null
|
367
424
|
this.pollNext = true
|
368
425
|
} catch (error) {
|
369
426
|
if (
|
370
|
-
error instanceof
|
371
|
-
retry < 8
|
427
|
+
error instanceof Deconz.ApiError && error.type === 101 && retry < 8
|
372
428
|
) {
|
373
429
|
this.log('unlock gateway to obtain API key - retrying in 15s')
|
374
430
|
await homebridgeLib.timeout(15000)
|
@@ -387,14 +443,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
387
443
|
* the gateway.
|
388
444
|
*/
|
389
445
|
async reset () {
|
390
|
-
if (this.
|
446
|
+
if (this.values.apiKey == null) {
|
391
447
|
return
|
392
448
|
}
|
393
449
|
try {
|
394
450
|
try {
|
395
|
-
await this.client.
|
451
|
+
await this.client.deleteApiKey()
|
396
452
|
} catch (error) {}
|
397
|
-
this.
|
453
|
+
this.values.apiKey = null
|
398
454
|
await this.wsClient.close()
|
399
455
|
for (const id in this.accessoryById) {
|
400
456
|
if (id !== this.id) {
|
@@ -406,12 +462,13 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
406
462
|
}
|
407
463
|
this.exposeErrors = {}
|
408
464
|
this.context.blacklist = {}
|
409
|
-
this.context.fullState =
|
465
|
+
this.context.fullState = null
|
410
466
|
this.service.values.lights = false
|
411
467
|
this.service.values.sensors = false
|
412
468
|
this.service.values.groups = false
|
413
469
|
this.service.values.schedules = false
|
414
|
-
this.service.values.
|
470
|
+
this.service.values.logLevel = 2
|
471
|
+
this.values.rtypes = []
|
415
472
|
} catch (error) { this.error(error) }
|
416
473
|
}
|
417
474
|
|
@@ -451,32 +508,15 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
451
508
|
if (this.deviceById[id] == null) {
|
452
509
|
throw new RangeError(`${id}: unknown device ID`)
|
453
510
|
}
|
454
|
-
if (this.unsupported[id] != null) {
|
455
|
-
return
|
456
|
-
}
|
457
511
|
if (this.accessoryById[id] == null) {
|
458
512
|
const device = this.deviceById[id]
|
459
|
-
this.debug(
|
460
|
-
'%s: new device, %d resources', id, device.rpaths.length
|
461
|
-
)
|
462
513
|
delete this.exposeErrorById[id]
|
463
|
-
const { body
|
514
|
+
const { body } = device.resource
|
515
|
+
this.log('%s: add accessory', body.name)
|
464
516
|
let { serviceName } = device.resource
|
465
|
-
if (category == null || serviceName == null) {
|
466
|
-
let message
|
467
|
-
if (category == null) {
|
468
|
-
message = util.format('%s: unknown %s type', body.type, rtype)
|
469
|
-
this.warn('%s: %s', body.name, message)
|
470
|
-
} else {
|
471
|
-
message = util.format('%s: unsupported %s type', body.type, rtype)
|
472
|
-
this.debug('%s: %s', body.name, message)
|
473
|
-
}
|
474
|
-
this.unsupported[id] = message
|
475
|
-
return
|
476
|
-
}
|
477
517
|
if (DeconzAccessory[serviceName] == null) {
|
478
|
-
this.warn('%s: %s: not yet supported %s type', body.name, body.type, rtype)
|
479
|
-
serviceName = '
|
518
|
+
// this.warn('%s: %s: not yet supported %s type', body.name, body.type, rtype)
|
519
|
+
serviceName = 'Sensor'
|
480
520
|
}
|
481
521
|
const accessory = new DeconzAccessory[serviceName](this, device)
|
482
522
|
this.accessoryById[id] = accessory
|
@@ -497,6 +537,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
497
537
|
throw new RangeError(`${id}: gateway ID`)
|
498
538
|
}
|
499
539
|
if (this.accessoryById[id] != null) {
|
540
|
+
this.log('%s: delete accessory', this.accessoryById[id].name)
|
500
541
|
this.monitorResources(this.accessoryById[id], false)
|
501
542
|
this.accessoryById[id].destroy()
|
502
543
|
delete this.accessoryById[id]
|
@@ -537,6 +578,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
537
578
|
/** Reset expose error for device.
|
538
579
|
*
|
539
580
|
* Remove the un-exposed accessory, so it will be re-created on next poll.
|
581
|
+
* @params {string} id - The device ID.
|
540
582
|
*/
|
541
583
|
resetExposeError (id) {
|
542
584
|
this.log(
|
@@ -546,7 +588,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
546
588
|
this.deleteService(id)
|
547
589
|
}
|
548
590
|
|
549
|
-
/** Add a service to the gateway accessory to un-blacklist
|
591
|
+
/** Add a service to the gateway accessory to un-blacklist a device.
|
550
592
|
* @params {string} id - The device ID.
|
551
593
|
* @return {DeconzService.DeviceSettings} - The service delegate.
|
552
594
|
*/
|
@@ -558,6 +600,9 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
558
600
|
throw new RangeError(`${id}: unknown device ID`)
|
559
601
|
}
|
560
602
|
if (this.serviceById[id] == null) {
|
603
|
+
if (Object.keys(this.serviceById).length >= 97) {
|
604
|
+
return null
|
605
|
+
}
|
561
606
|
const { resource, rpaths } = this.deviceById[id]
|
562
607
|
const { body } = resource
|
563
608
|
const service = new DeconzService.DeviceSettings(this, {
|
@@ -571,12 +616,12 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
571
616
|
return this.serviceById[id]
|
572
617
|
}
|
573
618
|
|
574
|
-
/** Delete the service on the gateway accessory to un-blacklist
|
619
|
+
/** Delete the service on the gateway accessory to un-blacklist a device.
|
575
620
|
* @params {string} id - The device ID.
|
576
621
|
*/
|
577
622
|
deleteService (id) {
|
578
623
|
if (id === this.id) {
|
579
|
-
|
624
|
+
throw new RangeError(`${id}: gateway ID`)
|
580
625
|
}
|
581
626
|
if (this.serviceById[id] != null) {
|
582
627
|
this.serviceById[id].destroy()
|
@@ -588,39 +633,39 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
588
633
|
|
589
634
|
/** Poll the gateway.
|
590
635
|
*
|
591
|
-
* Periodically
|
592
|
-
*
|
593
|
-
* a map of zigbee and virtual devices exposed by the gateway, while:
|
594
|
-
* - Creating new accessories for new devices;
|
595
|
-
* - Updating existing accessories for existing devices;
|
596
|
-
* - Deleting existing accessories for deleted devices.
|
636
|
+
* Periodically get the gateway full state and call
|
637
|
+
* {@link DeconzAccessory.Gateway#analyseFullState()}.<br>
|
597
638
|
*/
|
598
639
|
async poll () {
|
599
|
-
if (this.polling || this.
|
640
|
+
if (this.polling || this.values.apiKey == null) {
|
600
641
|
return
|
601
642
|
}
|
602
643
|
try {
|
603
644
|
this.polling = true
|
604
645
|
this.vdebug('%spolling...', this.pollNext ? 'priority ' : '')
|
605
|
-
|
606
|
-
|
607
|
-
this.service.values.expose = false
|
608
|
-
this.service.values.username = null
|
609
|
-
await this.wsClient.close()
|
610
|
-
return
|
611
|
-
}
|
612
|
-
this.context.fullState = { config: config }
|
613
|
-
this.update(this.context.fullState.config)
|
614
|
-
if (this.service.values.lights || this.service.values.sensors) {
|
615
|
-
this.context.fullState.lights = await this.client.get('/lights')
|
616
|
-
this.context.fullState.sensors = await this.client.get('/sensors')
|
617
|
-
}
|
618
|
-
if (this.service.values.groups) {
|
619
|
-
this.context.fullState.groups = await this.client.get('/groups')
|
646
|
+
if (this.context.fullState == null) {
|
647
|
+
this.context.fullState = await this.client.get('/')
|
620
648
|
this.context.fullState.groups[0] = await this.client.get('/groups/0')
|
621
|
-
}
|
622
|
-
|
623
|
-
|
649
|
+
} else {
|
650
|
+
const config = await this.client.get('/config')
|
651
|
+
if (config.bridgeid === this.id && config.UTC == null) {
|
652
|
+
this.service.values.expose = false
|
653
|
+
this.values.apiKey = null
|
654
|
+
await this.wsClient.close()
|
655
|
+
return
|
656
|
+
}
|
657
|
+
this.context.fullState.config = config
|
658
|
+
if (this.service.values.lights || this.service.values.sensors) {
|
659
|
+
this.context.fullState.lights = await this.client.get('/lights')
|
660
|
+
this.context.fullState.sensors = await this.client.get('/sensors')
|
661
|
+
}
|
662
|
+
if (this.service.values.groups) {
|
663
|
+
this.context.fullState.groups = await this.client.get('/groups')
|
664
|
+
this.context.fullState.groups[0] = await this.client.get('/groups/0')
|
665
|
+
}
|
666
|
+
if (this.service.values.schedules) {
|
667
|
+
this.context.fullState.schedules = await this.client.get('/schedules')
|
668
|
+
}
|
624
669
|
}
|
625
670
|
this.analyseFullState(this.context.fullState)
|
626
671
|
} catch (error) {
|
@@ -632,23 +677,71 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
632
677
|
}
|
633
678
|
}
|
634
679
|
|
635
|
-
|
636
|
-
|
637
|
-
|
680
|
+
/** Analyse the peristed full state of the gateway,
|
681
|
+
* adding, re-configuring, and deleting delegates for corresponding HomeKit
|
682
|
+
* accessories and services.
|
683
|
+
*
|
684
|
+
* The analysis consists of the following steps:
|
685
|
+
* 1. Analyse the resources, updating:
|
686
|
+
* {@link DeconzAccessory.Gateway#deviceById deviceById},
|
687
|
+
* {@link DeconzAccessory.Gateway#deviceByRidByRtype deviceByRidByRtype},
|
688
|
+
* {@link DeconzAccessory.Gateway#nDevices nDevices},
|
689
|
+
* {@link DeconzAccessory.Gateway#nDevicesByRtype nDevicesByRtype},
|
690
|
+
* {@link DeconzAccessory.Gateway#nResources nResources},
|
691
|
+
* {@link DeconzAccessory.Gateway#resourceByRpath resourceByRpath}.
|
692
|
+
* 2. Analyse (pre-existing) _Device_ accessories, emitting
|
693
|
+
* {@link DeconzAccessory.Device#event.polled}, and calling
|
694
|
+
* {@link DeconzAccessory.Gateway#deleteAccessory deleteAccessory()} for
|
695
|
+
* stale accessories, corresponding to devices that have been deleted from
|
696
|
+
* the gateway, blacklisted, or excluded by device primary resource type.
|
697
|
+
* 3. Analyse (pre-existing) _Device Settings_ services, calling
|
698
|
+
* {@link DeconzAccessory.Gateway#deleteService deleteService()}
|
699
|
+
* for stale services, corresponding to devices that have been deleted from
|
700
|
+
* the gateway, un-blacklisted, or excluded by device primary resource type.
|
701
|
+
* 4. Analysing supported devices with enabled device primary resource types,
|
702
|
+
* calling {@link DeconzAccessory.Gateway#addAccessory addAccessory()} and
|
703
|
+
* {@link DeconzAccessory.Gateway#deleteService deleteService()} for new
|
704
|
+
* _Device_ accessories, corresponding to devices added to the gateway,
|
705
|
+
* un-blacklisted, or included by device primary resource type, and calling
|
706
|
+
* {@link DeconzAccessory.Gateway#addService addService()} and
|
707
|
+
* {@link DeconzAccessory.Gateway#deleteAccessory deleteAccessory()} for
|
708
|
+
* accessories, corresponding to devices have been blacklisted.
|
709
|
+
* @param {Object} fullState - The gateway full state, as returned by
|
710
|
+
* {@link DeconzAccessory.Gateway#poll poll()}.
|
711
|
+
* @param {Object} params - Parameters
|
712
|
+
* @param {boolean} [params.logUnsupportedResources=false] - Issue debug
|
713
|
+
* messsages for unsupported resources.
|
714
|
+
* @param {boolean} [params.analyseOnly=false]
|
715
|
+
*/
|
716
|
+
analyseFullState (fullState, params = {}) {
|
717
|
+
/** Supported devices by device ID.
|
718
|
+
*
|
719
|
+
* Updated by
|
720
|
+
* {@link DeconzAccessory.Gateway#analyseFullState analyseFullState()}.
|
721
|
+
* @type {Object<string, Deconz.Device>}
|
638
722
|
*/
|
639
723
|
this.deviceById = {}
|
640
724
|
|
641
|
-
/**
|
642
|
-
*
|
725
|
+
/** Supported resources by resource path.
|
726
|
+
*
|
727
|
+
* Updated by {@link DeconzAccessory.Gateway#analyseFullState analyseFullState()}.
|
728
|
+
* @type {Object<string, Deconz.Resource>}
|
643
729
|
*/
|
644
730
|
this.resourceByRpath = {}
|
645
731
|
|
646
|
-
/**
|
647
|
-
*
|
732
|
+
/** Supported devices by resource ID by resource type, of the primary
|
733
|
+
* resource for the device.
|
734
|
+
*
|
735
|
+
* Updated by
|
736
|
+
* {@link DeconzAccessory.Gateway#analyseFullState analyseFullState()}.
|
737
|
+
* @type {Object<string, Object<string, Deconz.Device>>}
|
648
738
|
*/
|
649
739
|
this.deviceByRidByRtype = {}
|
650
740
|
|
651
|
-
/**
|
741
|
+
/** Number of supported devices by resource type.
|
742
|
+
*
|
743
|
+
* Updated by
|
744
|
+
* {@link DeconzAccessory.Gateway#analyseFullState analyseFullState()}.
|
652
745
|
* @type {Object<string, integer>}
|
653
746
|
*/
|
654
747
|
this.nDevicesByRtype = {}
|
@@ -657,12 +750,30 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
657
750
|
for (const rtype of rtypes) {
|
658
751
|
this.deviceByRidByRtype[rtype] = {}
|
659
752
|
for (const rid in fullState[rtype]) {
|
660
|
-
|
661
|
-
|
753
|
+
try {
|
754
|
+
const body = fullState[rtype][rid]
|
755
|
+
this.analyseResource(rtype, rid, body, params.logUnsupported)
|
756
|
+
} catch (error) { this.error(error) }
|
662
757
|
}
|
663
758
|
}
|
759
|
+
|
760
|
+
/** Number of supported devices.
|
761
|
+
*
|
762
|
+
* Updated by
|
763
|
+
* {@link DeconzAccessory.Gateway#analyseFullState analyseFullState()}.
|
764
|
+
* @type {integer}
|
765
|
+
*/
|
766
|
+
|
664
767
|
this.nDevices = Object.keys(this.deviceById).length
|
768
|
+
|
769
|
+
/** Number of supported resources.
|
770
|
+
*
|
771
|
+
* Updated by
|
772
|
+
* {@link DeconzAccessory.Gateway#analyseFullState analyseFullState()}.
|
773
|
+
* @type {integer}
|
774
|
+
*/
|
665
775
|
this.nResources = Object.keys(this.resourceByRpath).length
|
776
|
+
|
666
777
|
this.vdebug('%d devices, %d resources', this.nDevices, this.nResources)
|
667
778
|
for (const id in this.deviceById) {
|
668
779
|
const device = this.deviceById[id]
|
@@ -675,76 +786,87 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
675
786
|
this.vdebug('%d %s devices', this.nDevicesByRtype[rtype], rtype)
|
676
787
|
}
|
677
788
|
|
789
|
+
if (params.analyseOnly) {
|
790
|
+
return
|
791
|
+
}
|
792
|
+
|
793
|
+
this.update(fullState.config)
|
794
|
+
|
678
795
|
let changed = false
|
679
796
|
|
680
797
|
this.vdebug('analysing accessories...')
|
681
798
|
for (const id in this.accessoryById) {
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
this.nAccessories = Object.keys(this.accessoryById).length
|
699
|
-
this.nExposeErrors = Object.keys(this.exposeErrorById).length
|
700
|
-
if (this.nExposeErrors === 0) {
|
701
|
-
this.vdebug('%d accessories', this.nAccessories)
|
702
|
-
} else {
|
703
|
-
this.vdebug(
|
704
|
-
'%d accessories, %d expose errors', this.nAccessories, this.nExposeErrors
|
705
|
-
)
|
799
|
+
try {
|
800
|
+
if (
|
801
|
+
this.deviceById[id] == null
|
802
|
+
) {
|
803
|
+
delete this.context.blacklist[id]
|
804
|
+
this.deleteAccessory(id)
|
805
|
+
this.deleteService(id)
|
806
|
+
changed = true
|
807
|
+
} else {
|
808
|
+
/** Emitted when the gateway has been polled.
|
809
|
+
* @event DeconzAccessory.Device#polled
|
810
|
+
* @param {Deconz.Device} device - The updated device.
|
811
|
+
*/
|
812
|
+
this.accessoryById[id].emit('polled', this.deviceById[id])
|
813
|
+
}
|
814
|
+
} catch (error) { this.error(error) }
|
706
815
|
}
|
707
816
|
|
708
817
|
this.vdebug('analysing services...')
|
709
818
|
for (const id in this.serviceById) {
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
819
|
+
try {
|
820
|
+
if (
|
821
|
+
this.deviceById[id] == null ||
|
822
|
+
!this.values.rtypes.includes(this.deviceById[id].resource.rtype)
|
823
|
+
) {
|
824
|
+
delete this.exposeErrorById[id]
|
825
|
+
this.deleteService(id)
|
826
|
+
changed = true
|
827
|
+
}
|
828
|
+
} catch (error) { this.error(error) }
|
719
829
|
}
|
720
830
|
|
721
|
-
for (const rtype of this.
|
831
|
+
for (const rtype of this.values.rtypes) {
|
722
832
|
this.vdebug('analysing %s devices...', rtype)
|
723
833
|
const rids = Object.keys(this.deviceByRidByRtype[rtype]).sort()
|
724
834
|
for (const rid of rids) {
|
725
|
-
|
726
|
-
|
727
|
-
if (this.
|
728
|
-
this.
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
this.
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
this.
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
this.
|
742
|
-
|
835
|
+
try {
|
836
|
+
const { id } = this.deviceByRidByRtype[rtype][rid]
|
837
|
+
if (this.context.blacklist[id] == null) {
|
838
|
+
if (this.accessoryById[id] == null) {
|
839
|
+
this.addAccessory(id)
|
840
|
+
changed = true
|
841
|
+
}
|
842
|
+
if (this.serviceById[id] != null) {
|
843
|
+
this.deleteService(id)
|
844
|
+
changed = true
|
845
|
+
}
|
846
|
+
} else {
|
847
|
+
if (this.serviceById[id] == null) {
|
848
|
+
this.addService(id)
|
849
|
+
changed = true
|
850
|
+
}
|
851
|
+
if (this.accessoryById[id] != null) {
|
852
|
+
this.deleteAccessory(id)
|
853
|
+
changed = true
|
854
|
+
}
|
743
855
|
}
|
744
|
-
}
|
856
|
+
} catch (error) { this.error(error) }
|
745
857
|
}
|
746
858
|
}
|
747
859
|
|
860
|
+
this.nAccessories = Object.keys(this.accessoryById).length
|
861
|
+
this.nExposeErrors = Object.keys(this.exposeErrorById).length
|
862
|
+
if (this.nExposeErrors === 0) {
|
863
|
+
this.vdebug('%d accessories', this.nAccessories)
|
864
|
+
} else {
|
865
|
+
this.vdebug(
|
866
|
+
'%d accessories, %d expose errors', this.nAccessories, this.nExposeErrors
|
867
|
+
)
|
868
|
+
}
|
869
|
+
|
748
870
|
if (changed) {
|
749
871
|
this.nResourcesMonitored = Object.keys(this.accessoryByRpath).length
|
750
872
|
this.identify()
|
@@ -753,226 +875,46 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
753
875
|
}
|
754
876
|
}
|
755
877
|
|
756
|
-
/** Anayse a resource, updating
|
878
|
+
/** Anayse a gateway resource, updating
|
757
879
|
* {@link DeconzAccessory.Gateway#deviceById deviceById} and
|
758
|
-
* {@link DeconzAccessory.Gateway#resourceByRpath resourceByRpath}
|
880
|
+
* {@link DeconzAccessory.Gateway#resourceByRpath resourceByRpath} for
|
881
|
+
* supported resources.
|
759
882
|
*
|
760
883
|
* @param {string} rtype - The type of the resource:
|
761
|
-
* `
|
884
|
+
* `groups`, `lights`, or `sensors`.
|
762
885
|
* @param {integer} rid - The resource ID of the resource.
|
763
886
|
* @param {object} body - The body of the resource.
|
887
|
+
* @param {boolean} logUnsupported - Issue a debug message for
|
888
|
+
* unsupported resources.
|
764
889
|
*/
|
765
|
-
analyseResource (rtype, rid, body) {
|
766
|
-
const
|
767
|
-
const { id } =
|
768
|
-
if (id === this.id) {
|
890
|
+
analyseResource (rtype, rid, body, logUnsupported) {
|
891
|
+
const resource = new Deconz.Resource(this, rtype, rid, body)
|
892
|
+
const { id, serviceName } = resource
|
893
|
+
if (id === this.id || serviceName === '') {
|
894
|
+
const debug = (logUnsupported ? this.debug : this.vdebug).bind(this)
|
895
|
+
debug(
|
896
|
+
'%s: /%s/%d: %s: ignoring unsupported %s type',
|
897
|
+
id, rtype, rid, body.type, rtype
|
898
|
+
)
|
899
|
+
return
|
900
|
+
}
|
901
|
+
if (serviceName == null) {
|
902
|
+
const warn = (logUnsupported ? this.warn : this.vdebug).bind(this)
|
903
|
+
warn(
|
904
|
+
'%s: /%s/%d: %s: ignoring unknown %s type',
|
905
|
+
id, rtype, rid, body.type, rtype
|
906
|
+
)
|
769
907
|
return
|
770
908
|
}
|
771
909
|
if (this.deviceById[id] == null) {
|
772
|
-
this.deviceById[id] = new
|
910
|
+
this.deviceById[id] = new Deconz.Device(resource)
|
773
911
|
this.vdebug('%s: device', id)
|
912
|
+
} else {
|
913
|
+
this.deviceById[id].addResource(resource)
|
774
914
|
}
|
775
|
-
const resource = this.deviceById[id].addResource(rtype, rid, body, attrs)
|
776
915
|
const { rpath } = resource
|
777
|
-
this.vdebug('%s: %s: device resource', id, rpath)
|
778
916
|
this.resourceByRpath[rpath] = resource
|
779
|
-
|
780
|
-
|
781
|
-
/** Determine the derived attributes for a resource.
|
782
|
-
*
|
783
|
-
* @param {string} rtype - The type of the resource:
|
784
|
-
* `config`, `group`, `light`, or `sensor`.
|
785
|
-
* @param {integer} rid - The resource ID of the resource.
|
786
|
-
* @param {object} body - The body of the resource.
|
787
|
-
* @returns {DeconzDevice.ResourceAttributes} - The derived
|
788
|
-
* resource attributes.
|
789
|
-
*/
|
790
|
-
resourceAttrs (rtype, rid, body) {
|
791
|
-
toString('params.rtype', rtype, true)
|
792
|
-
if (!(rtypes.includes(rtype))) {
|
793
|
-
throw new RangeError(`rtype: ${rtype}: not a valid resource type`)
|
794
|
-
}
|
795
|
-
toInt('rid', rid)
|
796
|
-
toObject('body', body)
|
797
|
-
toString('body.name', body.name, true)
|
798
|
-
toString('body.type', body.type, true)
|
799
|
-
if (rtype === 'lights' || (rtype === 'sensors' && body.type.startsWith('Z'))) {
|
800
|
-
const { mac, endpoint, cluster } = parseUniqueid(body.uniqueid)
|
801
|
-
return new DeconzDevice.ResourceAttributes(
|
802
|
-
mac,
|
803
|
-
endpoint + (cluster == null ? '' : '-' + cluster),
|
804
|
-
rtype === 'lights'
|
805
|
-
? this.lightsTypeAttributes(body.type)
|
806
|
-
: this.sensorsTypeAttributes(body.type),
|
807
|
-
true
|
808
|
-
)
|
809
|
-
}
|
810
|
-
if (rtype === 'groups') {
|
811
|
-
return new DeconzDevice.ResourceAttributes(
|
812
|
-
this.id + '-G' + rid,
|
813
|
-
'G' + rid,
|
814
|
-
new DeconzDevice.TypeAttributes(
|
815
|
-
this.Accessory.Categories.LIGHTBULB, 'LightBulb'
|
816
|
-
),
|
817
|
-
false
|
818
|
-
)
|
819
|
-
}
|
820
|
-
return new DeconzDevice.ResourceAttributes(
|
821
|
-
this.id + '-S' + rid,
|
822
|
-
'S' + rid,
|
823
|
-
this.sensorsTypeAttributes(body.type),
|
824
|
-
false
|
825
|
-
)
|
826
|
-
}
|
827
|
-
|
828
|
-
/** Derive the attributes for a `/lights` resource type.
|
829
|
-
*
|
830
|
-
* @params {string} type - The `type` attribute of the `/lights` resource.
|
831
|
-
* @return {DeconzDevice.TypeAttributes} - The derived type
|
832
|
-
* attributes.
|
833
|
-
*/
|
834
|
-
lightsTypeAttributes (type) {
|
835
|
-
const Cats = this.Accessory.Categories
|
836
|
-
switch (type) {
|
837
|
-
case 'Color dimmable light':
|
838
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'LightBulb', 4)
|
839
|
-
case 'Color light':
|
840
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'LightBulb', 3)
|
841
|
-
case 'Color temperature light':
|
842
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'LightBulb', 2)
|
843
|
-
case 'Dimmable light':
|
844
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'LightBulb', 1)
|
845
|
-
case 'Dimmable plug-in unit':
|
846
|
-
return new DeconzDevice.TypeAttributes(Cats.OUTLET, 'LightBulb')
|
847
|
-
case 'Extended color light':
|
848
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'LightBulb', 5)
|
849
|
-
// case 'Consumption awareness device':
|
850
|
-
// return new DeconzDevice.TypeAttributes(Cats.OTHER)
|
851
|
-
case 'Dimmer switch':
|
852
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'LightBulb')
|
853
|
-
case 'Level control switch':
|
854
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'LightBulb')
|
855
|
-
// case 'Level controllable output':
|
856
|
-
// return new DeconzDevice.TypeAttributes(Cats.OTHER)
|
857
|
-
// case 'Door Lock':
|
858
|
-
// return new DeconzDevice.TypeAttributes(Cats.DOOR_LOCK)
|
859
|
-
// case 'Door Lock Unit':
|
860
|
-
// return new DeconzDevice.TypeAttributes(Cats.DOOR_LOCK)
|
861
|
-
// case 'Fan':
|
862
|
-
// return new DeconzDevice.TypeAttributes(Cats.FAN)
|
863
|
-
case 'On/Off light switch':
|
864
|
-
return new DeconzDevice.TypeAttributes(Cats.SWITCH, 'Outlet')
|
865
|
-
case 'On/Off light':
|
866
|
-
return new DeconzDevice.TypeAttributes(Cats.LIGHTBULB, 'Outlet')
|
867
|
-
case 'On/Off output':
|
868
|
-
return new DeconzDevice.TypeAttributes(Cats.OUTLET, 'Outlet')
|
869
|
-
case 'On/Off plug-in unit':
|
870
|
-
return new DeconzDevice.TypeAttributes(Cats.OUTLET, 'Outlet')
|
871
|
-
case 'Smart plug':
|
872
|
-
return new DeconzDevice.TypeAttributes(Cats.OUTLET, 'Outlet')
|
873
|
-
case 'Configuration tool':
|
874
|
-
return new DeconzDevice.TypeAttributes(Cats.BRIDGE)
|
875
|
-
case 'Range extender':
|
876
|
-
return new DeconzDevice.TypeAttributes(Cats.RANGE_EXTENDER)
|
877
|
-
case 'Warning device':
|
878
|
-
return new DeconzDevice.TypeAttributes(Cats.SECURITY_SYSTEM, 'WarningDevice')
|
879
|
-
case 'Window covering controller':
|
880
|
-
return new DeconzDevice.TypeAttributes(Cats.WINDOW_COVERING, 'WindowCovering')
|
881
|
-
case 'Window covering device':
|
882
|
-
return new DeconzDevice.TypeAttributes(Cats.WINDOW_COVERING, 'WindowCovering')
|
883
|
-
default:
|
884
|
-
return new DeconzDevice.TypeAttributes()
|
885
|
-
}
|
886
|
-
}
|
887
|
-
|
888
|
-
/** Derivce the attributes for a `/sensors` resource type.
|
889
|
-
*
|
890
|
-
* @params {string} type - The `type` attribute of the `/sensors` resource.
|
891
|
-
* @return {DeconzDevice.TypeAttributes} - The derived type
|
892
|
-
* attributes.
|
893
|
-
*/
|
894
|
-
sensorsTypeAttributes (type) {
|
895
|
-
const Cats = this.Accessory.Categories
|
896
|
-
switch (type) {
|
897
|
-
case 'ZHAAirPurifier':
|
898
|
-
case 'CLIPAirPurifier':
|
899
|
-
return new DeconzDevice.TypeAttributes(Cats.AIR_PURIFIER)
|
900
|
-
case 'ZHAAirQuality':
|
901
|
-
case 'CLIPAirQuality':
|
902
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'AirQuality', 3)
|
903
|
-
case 'ZHAAlarm':
|
904
|
-
case 'CLIPAlarm':
|
905
|
-
return new DeconzDevice.TypeAttributes(Cats.SECURITY_SYSTEM, 'Alarm')
|
906
|
-
// case 'ZHAAncillaryControl':
|
907
|
-
// case 'CLIPAncillaryControl':
|
908
|
-
// return new DeconzDevice.TypeAttributes(Cats.SECURITY_SYSTEM)
|
909
|
-
case 'ZHABattery':
|
910
|
-
case 'CLIPBattery':
|
911
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Battery')
|
912
|
-
case 'ZHACarbonMonoxide':
|
913
|
-
case 'CLIPCarbonMonoxide':
|
914
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'CarbonMonoxide')
|
915
|
-
case 'ZHAConsumption':
|
916
|
-
case 'CLIPConsumption':
|
917
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Consumption')
|
918
|
-
// case 'ZHADoorLock':
|
919
|
-
// case 'CLIPDoorLock':
|
920
|
-
// return new DeconzDevice.TypeAttributes(Cats.DOOR_LOCK)
|
921
|
-
case 'Daylight':
|
922
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Daylight')
|
923
|
-
case 'ZHAFire':
|
924
|
-
case 'CLIPFire':
|
925
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Fire')
|
926
|
-
case 'CLIPGenericFlag':
|
927
|
-
return new DeconzDevice.TypeAttributes(Cats.SWITCH, 'Flag')
|
928
|
-
case 'CLIPGenericStatus':
|
929
|
-
return new DeconzDevice.TypeAttributes(Cats.OTHER, 'Status')
|
930
|
-
case 'ZHAHumidity':
|
931
|
-
case 'CLIPHumidity':
|
932
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Humidity', 4)
|
933
|
-
case 'ZHALightLevel':
|
934
|
-
case 'CLIPLightLevel':
|
935
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'LightLevel', 6)
|
936
|
-
// case 'ZHAMoisture':
|
937
|
-
// case 'CLIPMoisture':
|
938
|
-
// return new DeconzDevice.TypeAttributes(Cats.SENSOR)
|
939
|
-
case 'ZHAOpenClose':
|
940
|
-
case 'CLIPOpenClose':
|
941
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'OpenClose', 8)
|
942
|
-
case 'ZHAPower':
|
943
|
-
case 'CLIPPower':
|
944
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Power', 1)
|
945
|
-
case 'ZHAPresence':
|
946
|
-
case 'CLIPPresence':
|
947
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Presence', 7)
|
948
|
-
case 'ZHAPressure':
|
949
|
-
case 'CLIPPressure':
|
950
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Pressure', 3)
|
951
|
-
// case 'ZHASpectral':
|
952
|
-
// return new DeconzDevice.TypeAttributes(Cats.SENSOR)
|
953
|
-
case 'ZGPSwitch':
|
954
|
-
case 'ZHASwitch':
|
955
|
-
return new DeconzDevice.TypeAttributes(Cats.PROGRAMMABLE_SWITCH, 'Switch')
|
956
|
-
case 'CLIPSwitch':
|
957
|
-
return new DeconzDevice.TypeAttributes(Cats.PROGRAMMABLE_SWITCH)
|
958
|
-
case 'ZHATemperature':
|
959
|
-
case 'CLIPTemperature':
|
960
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Temperature', 5)
|
961
|
-
case 'ZHAThermostat':
|
962
|
-
case 'CLIPThermostat':
|
963
|
-
return new DeconzDevice.TypeAttributes(Cats.THERMOSTAT, 'Thermostat')
|
964
|
-
case 'ZHATime':
|
965
|
-
case 'CLIPTime':
|
966
|
-
return new DeconzDevice.TypeAttributes(Cats.OTHER)
|
967
|
-
case 'ZHAVibration':
|
968
|
-
case 'CLIPVibration':
|
969
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Vibration')
|
970
|
-
case 'ZHAWater':
|
971
|
-
case 'CLIPWater':
|
972
|
-
return new DeconzDevice.TypeAttributes(Cats.SENSOR, 'Water')
|
973
|
-
default:
|
974
|
-
return new DeconzDevice.TypeAttributes()
|
975
|
-
}
|
917
|
+
this.vdebug('%s: %s: device resource', id, rpath)
|
976
918
|
}
|
977
919
|
}
|
978
920
|
|