homebridge-lib 5.1.24-3 → 5.2.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/index.js +7 -0
- package/lib/AccessoryDelegate.js +103 -24
- package/lib/AdaptiveLighting.js +8 -2
- package/lib/CharacteristicDelegate.js +11 -2
- package/lib/EveHomeKitTypes.js +2 -1
- package/lib/MyHomeKitTypes.js +43 -6
- package/lib/Platform.js +59 -132
- package/lib/PropertyDelegate.js +135 -0
- package/lib/ServiceDelegate.js +16 -0
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -175,6 +175,13 @@ class homebridgeLib {
|
|
|
175
175
|
*/
|
|
176
176
|
static get Platform () { return require('./lib/Platform') }
|
|
177
177
|
|
|
178
|
+
/** Delegate of a property of a HomeKit accessory or service.
|
|
179
|
+
* <br>See {@link PropertyDelegate}.
|
|
180
|
+
* @type {Class}
|
|
181
|
+
* @memberof module:homebridgeLib
|
|
182
|
+
*/
|
|
183
|
+
static get PropertyDelegate () { return require('./lib/PropertyDelegate') }
|
|
184
|
+
|
|
178
185
|
/** Delegate of a HomeKit service.
|
|
179
186
|
* <br>See {@link ServiceDelegate}.
|
|
180
187
|
* @type {Class}
|
package/lib/AccessoryDelegate.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
const homebridgeLib = require('../index')
|
|
9
9
|
|
|
10
|
-
const maxLogLevel = 4
|
|
11
10
|
const startsWithUuid = /^[0-9A-F]{8}-[0-9A-F]{4}-[1-5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/
|
|
12
11
|
|
|
13
12
|
/** Delegate of a HomeKit accessory.
|
|
@@ -35,8 +34,6 @@ class AccessoryDelegate extends homebridgeLib.Delegate {
|
|
|
35
34
|
* @param {!string} params.firmware - The accessory firmware revision.
|
|
36
35
|
* @param {?string} params.hardware - The accessory hardware revision.
|
|
37
36
|
* @param {?string} params.software - The accessory software revision.
|
|
38
|
-
* @param {?boolean} [params.inheritLogLevel] - Inherit `logLevel` from
|
|
39
|
-
* `platform` instead of maintaining it oneself.
|
|
40
37
|
*/
|
|
41
38
|
constructor (platform, params = {}) {
|
|
42
39
|
if (params.name == null) {
|
|
@@ -50,19 +47,25 @@ class AccessoryDelegate extends homebridgeLib.Delegate {
|
|
|
50
47
|
throw new RangeError('params.id: invalid id')
|
|
51
48
|
}
|
|
52
49
|
|
|
53
|
-
if (params.inheritLogLevel != null) {
|
|
54
|
-
if (params.inheritLogLevel) {
|
|
55
|
-
Object.defineProperty(this, 'logLevel', {
|
|
56
|
-
get () { return platform.logLevel }
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
delete params.inheritLogLevel
|
|
60
|
-
}
|
|
61
|
-
|
|
62
50
|
// Link or create associated PlatformAccessory.
|
|
63
51
|
this._accessory = this._platform._getAccessory(this, params)
|
|
52
|
+
|
|
53
|
+
if (params.logLevel != null) {
|
|
54
|
+
this.warn('params.logLevel: deprecated')
|
|
55
|
+
}
|
|
56
|
+
if (params.inheritLogLevel != null) {
|
|
57
|
+
this.warn('params.inheritLogLevel: deprecated')
|
|
58
|
+
}
|
|
64
59
|
this._context = this._accessory.context
|
|
65
60
|
|
|
61
|
+
delete this._context.logLevel
|
|
62
|
+
|
|
63
|
+
// Setup shortcut for property values and values of the characteristics
|
|
64
|
+
// of the _Accessory Information_ service.
|
|
65
|
+
this._values = {} // by key
|
|
66
|
+
|
|
67
|
+
this._propertyDelegates = {}
|
|
68
|
+
|
|
66
69
|
// Create delegate for AccessoryInformation service.
|
|
67
70
|
this._serviceDelegates = {}
|
|
68
71
|
this._accessoryInformationDelegate =
|
|
@@ -135,16 +138,88 @@ class AccessoryDelegate extends homebridgeLib.Delegate {
|
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
140
|
|
|
141
|
+
/** Creates a new {@link PropertyDelegate} instance, for a property of the
|
|
142
|
+
* associated HomeKit accessory.
|
|
143
|
+
*
|
|
144
|
+
* The property value is accessed through
|
|
145
|
+
* {@link AccessoryDelegate#values values}.
|
|
146
|
+
* The delegate is returned, but can also be accessed through
|
|
147
|
+
* {@link AccessoryDelegate#propertyDelegate propertyDelegate()}.
|
|
148
|
+
* @param {!object} params - Parameters of the property delegate.
|
|
149
|
+
* @param {!string} params.key - The key for the property delegate.<br>
|
|
150
|
+
* Needs to be unique with parent delegate.
|
|
151
|
+
// * @param {!type} params.type - The type of the property value.
|
|
152
|
+
* @param {?*} params.value - The initial value of the property.<br>
|
|
153
|
+
* Only used when the property delegate is created for the first time.
|
|
154
|
+
* Otherwise, the value is restored from persistent storage.
|
|
155
|
+
* @param {?boolean} params.logLevel - Level for homebridge log messages
|
|
156
|
+
* when property was set or has been changed.
|
|
157
|
+
* @param {?string} params.unit - The unit of the value of the property.
|
|
158
|
+
* @throws {TypeError} When a parameter has an invalid type.
|
|
159
|
+
* @throws {RangeError} When a parameter has an invalid value.
|
|
160
|
+
* @throws {SyntaxError} When a mandatory parameter is missing or an
|
|
161
|
+
* optional parameter is not applicable.
|
|
162
|
+
* @returns {PropertyDelegate}
|
|
163
|
+
* @throws {TypeError} When a parameter has an invalid type.
|
|
164
|
+
* @throws {RangeError} When a parameter has an invalid value.
|
|
165
|
+
* @throws {SyntaxError} When a mandatory parameter is missing or an
|
|
166
|
+
* optional parameter is not applicable.
|
|
167
|
+
*/
|
|
168
|
+
addPropertyDelegate (params = {}) {
|
|
169
|
+
if (typeof params.key !== 'string') {
|
|
170
|
+
throw new TypeError(`params.key: ${params.key}: invalid key`)
|
|
171
|
+
}
|
|
172
|
+
if (params.key === '') {
|
|
173
|
+
throw new RangeError(`params.key: ${params.key}: invalid key`)
|
|
174
|
+
}
|
|
175
|
+
const key = params.key
|
|
176
|
+
if (this.values[key] !== undefined) {
|
|
177
|
+
throw new SyntaxError(`${key}: duplicate key`)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const delegate = new homebridgeLib.PropertyDelegate(this, params)
|
|
181
|
+
this._propertyDelegates[key] = delegate
|
|
182
|
+
|
|
183
|
+
// Create shortcut for characteristic value.
|
|
184
|
+
Object.defineProperty(this.values, key, {
|
|
185
|
+
configurable: true, // make sure we can delete it again
|
|
186
|
+
writeable: true,
|
|
187
|
+
get () { return delegate.value },
|
|
188
|
+
set (value) { delegate.value = value }
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
return delegate
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
removePropertyDelegate (key) {
|
|
195
|
+
if (this._accessoryInformationDelegate.values[key] != null) {
|
|
196
|
+
throw new RangeError('%s: invalid key')
|
|
197
|
+
}
|
|
198
|
+
delete this.values[key]
|
|
199
|
+
const delegate = this._propertyDelegates[key]
|
|
200
|
+
delegate._destroy()
|
|
201
|
+
delete this._propertyDelegates[key]
|
|
202
|
+
delete this._context[key]
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Returns the property delegate correspondig to the property key.
|
|
206
|
+
* @param {!string} key - The key for the property.
|
|
207
|
+
* returns {PropertyDelegate}
|
|
208
|
+
*/
|
|
209
|
+
propertyDelegate (key) {
|
|
210
|
+
return this._propertyDelegates[key]
|
|
211
|
+
}
|
|
212
|
+
|
|
138
213
|
/** Values of the HomeKit characteristics for the `AccessoryInformation` service.
|
|
139
214
|
*
|
|
140
|
-
* Contains the key of each characteristic in
|
|
215
|
+
* Contains the key of each property and of each characteristic in
|
|
141
216
|
* {@link ServiceDelegate.AccessoryInformation AccessoryInformation}.
|
|
142
217
|
* When the value is written, the value of the corresponding HomeKit
|
|
143
218
|
* characteristic is updated.
|
|
144
219
|
* @type {object}
|
|
145
220
|
*/
|
|
146
221
|
get values () {
|
|
147
|
-
return this.
|
|
222
|
+
return this._values
|
|
148
223
|
}
|
|
149
224
|
|
|
150
225
|
/** Enable `heartbeat` events for this accessory delegate.
|
|
@@ -189,16 +264,7 @@ class AccessoryDelegate extends homebridgeLib.Delegate {
|
|
|
189
264
|
* @type {!integer}
|
|
190
265
|
*/
|
|
191
266
|
get logLevel () {
|
|
192
|
-
return this.
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
set logLevel (value) {
|
|
196
|
-
const oldLogLevel = this._context.logLevel
|
|
197
|
-
this._context.logLevel = Math.max(0, Math.min(value, maxLogLevel))
|
|
198
|
-
this._platform._message(
|
|
199
|
-
'log', 2, this.name + ': ',
|
|
200
|
-
'set loglevel from %d to %d', oldLogLevel, this.logLevel
|
|
201
|
-
)
|
|
267
|
+
return this.platform.logLevel
|
|
202
268
|
}
|
|
203
269
|
|
|
204
270
|
/** Inherit `logLevel` from another accessory delegate.
|
|
@@ -217,6 +283,19 @@ class AccessoryDelegate extends homebridgeLib.Delegate {
|
|
|
217
283
|
})
|
|
218
284
|
}
|
|
219
285
|
|
|
286
|
+
/** Manage `logLevel` from characteristic delegate.
|
|
287
|
+
* @param {CharacteristicDelegate} delegate - The delegate of the `logLevel`
|
|
288
|
+
* characteristic.
|
|
289
|
+
*/
|
|
290
|
+
manageLogLevel (delegate) {
|
|
291
|
+
if (!(delegate instanceof homebridgeLib.CharacteristicDelegate)) {
|
|
292
|
+
throw new TypeError('delegate: not an CharacteristicDelegate')
|
|
293
|
+
}
|
|
294
|
+
Object.defineProperty(this, 'logLevel', {
|
|
295
|
+
get () { return delegate.value }
|
|
296
|
+
})
|
|
297
|
+
}
|
|
298
|
+
|
|
220
299
|
// Called by homebridge when Identify is selected.
|
|
221
300
|
_identify () {
|
|
222
301
|
this.emit('identify')
|
package/lib/AdaptiveLighting.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
const homebridgeLib = require('../index')
|
|
9
|
+
|
|
8
10
|
/* global BigInt */
|
|
9
11
|
|
|
10
12
|
const epoch = (new Date('2001-01-01T00:00:00Z')).valueOf()
|
|
@@ -170,8 +172,12 @@ class AdaptiveLighting {
|
|
|
170
172
|
* @param {integer} ct - The IID of the _Color Temperature_ characteristic.
|
|
171
173
|
*/
|
|
172
174
|
constructor (bri, ct) {
|
|
173
|
-
this.bri = bri
|
|
174
|
-
|
|
175
|
+
this.bri = bri instanceof homebridgeLib.CharacteristicDelegate
|
|
176
|
+
? bri._characteristic.iid
|
|
177
|
+
: bri
|
|
178
|
+
this.ct = ct instanceof homebridgeLib.CharacteristicDelegate
|
|
179
|
+
? ct._characteristic.iid
|
|
180
|
+
: ct
|
|
175
181
|
this._active = false
|
|
176
182
|
}
|
|
177
183
|
|
|
@@ -200,6 +200,10 @@ class CharacteristicDelegate extends homebridgeLib.Delegate {
|
|
|
200
200
|
return this._hasPerm(this.Characteristic.Perms.NOTIFY)
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
get _writeResponse () {
|
|
204
|
+
return this._hasPerm(this.Characteristic.Perms.WRITE_RESPONSE)
|
|
205
|
+
}
|
|
206
|
+
|
|
203
207
|
get _writeOnly () {
|
|
204
208
|
return this._canWrite && !this._canRead && !this._canNotifiy
|
|
205
209
|
}
|
|
@@ -375,6 +379,7 @@ class CharacteristicDelegate extends homebridgeLib.Delegate {
|
|
|
375
379
|
// Called when characteristic is updated from HomeKit.
|
|
376
380
|
async _onSet (v, callback) {
|
|
377
381
|
const { value } = this.validate(v)
|
|
382
|
+
let result
|
|
378
383
|
|
|
379
384
|
// Issue info message that Characteristic value was updated from HomeKit.
|
|
380
385
|
if (this._writeOnly || this.value == null) {
|
|
@@ -407,7 +412,7 @@ class CharacteristicDelegate extends homebridgeLib.Delegate {
|
|
|
407
412
|
callback(new Error('timed out'))
|
|
408
413
|
}, this._timeout)
|
|
409
414
|
try {
|
|
410
|
-
await this._setter(value)
|
|
415
|
+
result = await this._setter(value)
|
|
411
416
|
} catch (error) {
|
|
412
417
|
clearTimeout(timeout)
|
|
413
418
|
this.error(error)
|
|
@@ -423,7 +428,11 @@ class CharacteristicDelegate extends homebridgeLib.Delegate {
|
|
|
423
428
|
}
|
|
424
429
|
|
|
425
430
|
// Return status to HomeKit.
|
|
426
|
-
|
|
431
|
+
if (this._writeResponse) {
|
|
432
|
+
callback(null, result)
|
|
433
|
+
} else {
|
|
434
|
+
callback()
|
|
435
|
+
}
|
|
427
436
|
|
|
428
437
|
// Update persisted value in ~/.homebridge/accessories/cachedAccessories.
|
|
429
438
|
this._serviceDelegate._context[this._key] = value
|
package/lib/EveHomeKitTypes.js
CHANGED
|
@@ -188,10 +188,11 @@ class EveHomeKitTypes extends homebridgeLib.CustomHomeKitTypes {
|
|
|
188
188
|
}, 'Current Consumption')
|
|
189
189
|
|
|
190
190
|
this.createCharacteristicClass('AirPressure', uuid('10F'), {
|
|
191
|
-
format: this.Formats.
|
|
191
|
+
format: this.Formats.FLOAT,
|
|
192
192
|
unit: 'hPa',
|
|
193
193
|
minValue: 700,
|
|
194
194
|
maxValue: 1100,
|
|
195
|
+
minStep: 0.1,
|
|
195
196
|
perms: [this.Perms.READ, this.Perms.NOTIFY]
|
|
196
197
|
}, 'Air Pressure')
|
|
197
198
|
|
package/lib/MyHomeKitTypes.js
CHANGED
|
@@ -83,8 +83,16 @@ class MyHomeKitTypes extends homebridgeLib.CustomHomeKitTypes {
|
|
|
83
83
|
* <br>Used by: homebridge-hue.
|
|
84
84
|
* @property {Class} Enabled - Enable/disable service.
|
|
85
85
|
* <br>Used by: homebridge-hue.
|
|
86
|
-
* @property {Class} Expose - Expose to HomeKit.
|
|
87
|
-
* <br>Used by: homebridge-deconz.
|
|
86
|
+
* @property {Class} Expose - Expose device to HomeKit.
|
|
87
|
+
* <br>Used by: homebridge-deconz, homebridge-hue2.
|
|
88
|
+
* @property {Class} ExposeGroups - Expose groups to HomeKit.
|
|
89
|
+
* <br>Used by: homebridge-deconz, homebridge-hue2.
|
|
90
|
+
* @property {Class} ExposeLights - Expose lights devices to HomeKit.
|
|
91
|
+
* <br>Used by: homebridge-deconz, homebridge-hue2.
|
|
92
|
+
* @property {Class} ExposeSchedules - Expose schdules to HomeKit.
|
|
93
|
+
* <br>Used by: homebridge-deconz, homebridge-hue2.
|
|
94
|
+
* @property {Class} ExposeSensors - Expose sensors devices to HomeKit.
|
|
95
|
+
* <br>Used by: homebridge-deconz, homebridge-hue2.
|
|
88
96
|
* @property {Class} Heartrate - Refresh rate.
|
|
89
97
|
* <br>Used by: homebridge-hue in HueBridge service,
|
|
90
98
|
* by Homebridge-soma, by Homebridge-rpi, by Homebridge-ws.
|
|
@@ -581,7 +589,7 @@ class MyHomeKitTypes extends homebridgeLib.CustomHomeKitTypes {
|
|
|
581
589
|
this.createCharacteristicClass('LogLevel', uuid('065'), {
|
|
582
590
|
format: this.Formats.UINT8,
|
|
583
591
|
minValue: 0,
|
|
584
|
-
maxValue: 3,
|
|
592
|
+
maxValue: 3, // 4 for homebridge-zp
|
|
585
593
|
minStep: 1, // Force Down|Up control in Eve
|
|
586
594
|
perms: [this.Perms.READ, this.Perms.NOTIFY, this.Perms.WRITE],
|
|
587
595
|
adminOnlyAccess: [this.Access.WRITE]
|
|
@@ -590,6 +598,7 @@ class MyHomeKitTypes extends homebridgeLib.CustomHomeKitTypes {
|
|
|
590
598
|
this.Characteristics.LogLevel.LOG = 1
|
|
591
599
|
this.Characteristics.LogLevel.DEBUG = 2
|
|
592
600
|
this.Characteristics.LogLevel.VDEBUG = 3
|
|
601
|
+
this.Characteristics.LogLevel.VVDEBUG = 4
|
|
593
602
|
|
|
594
603
|
this.createCharacteristicClass('Repeat', uuid('066'), {
|
|
595
604
|
format: this.Formats.UINT8,
|
|
@@ -714,6 +723,30 @@ class MyHomeKitTypes extends homebridgeLib.CustomHomeKitTypes {
|
|
|
714
723
|
adminOnlyAccess: [this.Access.WRITE]
|
|
715
724
|
})
|
|
716
725
|
|
|
726
|
+
this.createCharacteristicClass('ExposeLights', uuid('079'), {
|
|
727
|
+
format: this.Formats.BOOL,
|
|
728
|
+
perms: [this.Perms.READ, this.Perms.NOTIFY, this.Perms.WRITE],
|
|
729
|
+
adminOnlyAccess: [this.Access.WRITE]
|
|
730
|
+
}, 'Expose Lights')
|
|
731
|
+
|
|
732
|
+
this.createCharacteristicClass('ExposeSensors', uuid('07A'), {
|
|
733
|
+
format: this.Formats.BOOL,
|
|
734
|
+
perms: [this.Perms.READ, this.Perms.NOTIFY, this.Perms.WRITE],
|
|
735
|
+
adminOnlyAccess: [this.Access.WRITE]
|
|
736
|
+
}, 'Expose Sensors')
|
|
737
|
+
|
|
738
|
+
this.createCharacteristicClass('ExposeGroups', uuid('07B'), {
|
|
739
|
+
format: this.Formats.BOOL,
|
|
740
|
+
perms: [this.Perms.READ, this.Perms.NOTIFY, this.Perms.WRITE],
|
|
741
|
+
adminOnlyAccess: [this.Access.WRITE]
|
|
742
|
+
}, 'Expose Groups')
|
|
743
|
+
|
|
744
|
+
this.createCharacteristicClass('ExposeSchedules', uuid('07C'), {
|
|
745
|
+
format: this.Formats.BOOL,
|
|
746
|
+
perms: [this.Perms.READ, this.Perms.NOTIFY, this.Perms.WRITE],
|
|
747
|
+
adminOnlyAccess: [this.Access.WRITE]
|
|
748
|
+
}, 'Expose Schedules')
|
|
749
|
+
|
|
717
750
|
// Characteristic for Unique ID, used by homebridge-hue.
|
|
718
751
|
// Source: as exposed by the Philips Hue bridge. This characteristic is
|
|
719
752
|
// used by the Hue app to select the accessories when syncing Hue bridge
|
|
@@ -782,13 +815,17 @@ class MyHomeKitTypes extends homebridgeLib.CustomHomeKitTypes {
|
|
|
782
815
|
])
|
|
783
816
|
|
|
784
817
|
this.createServiceClass('DeconzGateway', uuid('014'), [
|
|
785
|
-
this.Characteristics.LogLevel,
|
|
786
|
-
this.Characteristics.Expose,
|
|
787
818
|
this.Characteristics.Heartrate,
|
|
788
819
|
this.Characteristics.LastUpdated,
|
|
820
|
+
this.Characteristics.TransitionTime,
|
|
821
|
+
this.Characteristics.Expose,
|
|
822
|
+
this.Characteristics.ExposeLights,
|
|
823
|
+
this.Characteristics.ExposeSensors,
|
|
824
|
+
this.Characteristics.ExposeGroups,
|
|
825
|
+
this.Characteristics.ExposeSchedules,
|
|
826
|
+
this.Characteristics.LogLevel,
|
|
789
827
|
this.Characteristics.Restart,
|
|
790
828
|
this.Characteristics.Search,
|
|
791
|
-
this.Characteristics.TransitionTime,
|
|
792
829
|
this.Characteristics.Unlock
|
|
793
830
|
])
|
|
794
831
|
|
package/lib/Platform.js
CHANGED
|
@@ -27,8 +27,6 @@ const context = {
|
|
|
27
27
|
checkInterval: 7 * 24 * 3600
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const globalKey = context.libName // + '@' + context.libVersion
|
|
31
|
-
|
|
32
30
|
/** Homebridge dynamic platform plugin.
|
|
33
31
|
*
|
|
34
32
|
* `Platform` provides the following features to a platform plugin:
|
|
@@ -59,6 +57,8 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
59
57
|
static loadPlatform (homebridge, packageJson, platformName, Platform) {
|
|
60
58
|
if (context.homebridge == null) {
|
|
61
59
|
context.homebridge = homebridge
|
|
60
|
+
context.packageJson = packageJson
|
|
61
|
+
context.platformName = platformName
|
|
62
62
|
context.homebridgeVersion = homebridge.serverVersion
|
|
63
63
|
context.PlatformAccessory = homebridge.platformAccessory
|
|
64
64
|
const hap = {
|
|
@@ -98,25 +98,6 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
98
98
|
my: Object.freeze(my.Characteristics)
|
|
99
99
|
})
|
|
100
100
|
}
|
|
101
|
-
if (global[globalKey] == null) {
|
|
102
|
-
global[globalKey] = {
|
|
103
|
-
Platform: {
|
|
104
|
-
platformName: context.libName,
|
|
105
|
-
packageJson: libPackageJson,
|
|
106
|
-
UpnpClient: homebridgeLib.UpnpClient
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
homebridge.registerPlatform(
|
|
110
|
-
// libPackageJson.name, 'Lib', homebridgeLib.Platform, false
|
|
111
|
-
packageJson.name, 'Lib', homebridgeLib.Platform, false
|
|
112
|
-
)
|
|
113
|
-
// } else {
|
|
114
|
-
// TODO: check compatible homebridge-lib version.
|
|
115
|
-
}
|
|
116
|
-
global[globalKey][Platform.name] = {
|
|
117
|
-
platformName: platformName,
|
|
118
|
-
packageJson: packageJson
|
|
119
|
-
}
|
|
120
101
|
homebridge.registerPlatform(
|
|
121
102
|
packageJson.name, platformName, Platform, true
|
|
122
103
|
)
|
|
@@ -148,50 +129,19 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
148
129
|
this._log = log
|
|
149
130
|
this._configJson = configJson
|
|
150
131
|
this._homebridge = homebridge
|
|
151
|
-
|
|
152
|
-
this.
|
|
153
|
-
this.
|
|
154
|
-
|
|
155
|
-
if (myContext.packageJson.name === context.libName) {
|
|
156
|
-
this._isHomebridgeLib = true
|
|
157
|
-
myContext.heartbeat = this
|
|
158
|
-
// Delay start of Homebridge's HAP server until all plugins have
|
|
159
|
-
// initialised.
|
|
160
|
-
this.accessories = (f) => {
|
|
161
|
-
this.on('initialised', () => { f([]) })
|
|
162
|
-
}
|
|
163
|
-
// this.debug('Categories: %j', this.Accessory.Categories)
|
|
164
|
-
// for (const type of ['Access', 'Formats', 'Perms', 'Units']) {
|
|
165
|
-
// this.debug('%s: %j', type, this.Characteristic[type])
|
|
166
|
-
// }
|
|
167
|
-
// for (const module of ['hap', 'eve', 'my']) {
|
|
168
|
-
// this.debug('Services.%s: %j', module, Object.keys(this.Services[module]))
|
|
169
|
-
// this.debug('Characteristics.%s: %j', module, Object.keys(this.Characteristics[module]))
|
|
170
|
-
// }
|
|
171
|
-
} else {
|
|
172
|
-
/** Configure an accessory, after it has been restored from peristent
|
|
173
|
-
* storage.
|
|
174
|
-
*
|
|
175
|
-
* Called by homebridge when restoring peristed accessories, typically from
|
|
176
|
-
* `~/.homebridge/accessories/cachedAccessories`.
|
|
177
|
-
* @method
|
|
178
|
-
* @param {!PlatformAccessory} accessory - The restored Homebridge
|
|
179
|
-
* [PlatformAccessory](https://github.com/nfarina/homebridge/blob/master/lib/platformAccessory.js).
|
|
180
|
-
*/
|
|
181
|
-
this.configureAccessory = this._configureAccessory
|
|
182
|
-
}
|
|
132
|
+
this._platformName = context.platformName
|
|
133
|
+
this._pluginName = context.packageJson.name
|
|
134
|
+
this._pluginVersion = context.packageJson.version
|
|
135
|
+
|
|
183
136
|
this._accessories = {}
|
|
184
137
|
this._accessoryDelegates = {}
|
|
185
138
|
|
|
186
|
-
if (
|
|
139
|
+
if (context.platform != null) {
|
|
187
140
|
this.fatal(
|
|
188
|
-
'config.json: duplicate entry for %s platform',
|
|
141
|
+
'config.json: duplicate entry for %s platform', context.platformName
|
|
189
142
|
)
|
|
190
143
|
}
|
|
191
|
-
|
|
192
|
-
if (global[globalKey].Platform == null) {
|
|
193
|
-
this.fatal('%s platform not registered', context.libName)
|
|
194
|
-
}
|
|
144
|
+
context.platform = this
|
|
195
145
|
this._identify()
|
|
196
146
|
|
|
197
147
|
this._homebridge
|
|
@@ -205,54 +155,30 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
205
155
|
// Main platform function.
|
|
206
156
|
// Called by homebridge after restoring accessories from cache.
|
|
207
157
|
async _main () {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
this.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
this.
|
|
229
|
-
this.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
this.debug('flush cachedAccessories')
|
|
233
|
-
this._homebridge.updatePlatformAccessories()
|
|
234
|
-
this.log('goodbye')
|
|
235
|
-
})
|
|
236
|
-
} else {
|
|
237
|
-
this.systemInfo = global[globalKey].Platform.heartbeat.systemInfo
|
|
238
|
-
}
|
|
239
|
-
if (this._isHomebridgeLib) {
|
|
240
|
-
const jobs = []
|
|
241
|
-
for (const plugin in global[globalKey]) {
|
|
242
|
-
const platform = global[globalKey][plugin].platform
|
|
243
|
-
if (
|
|
244
|
-
platform != null && platform !== this &&
|
|
245
|
-
Object.keys(platform._accessories).length === 0
|
|
246
|
-
) {
|
|
247
|
-
this.warn('waiting on %s', plugin)
|
|
248
|
-
jobs.push(events.once(platform, 'initialised'))
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
for (const job of jobs) {
|
|
252
|
-
await job
|
|
253
|
-
}
|
|
254
|
-
this.emit('initialised')
|
|
255
|
-
}
|
|
158
|
+
// process.on('unhandledRejection', (error) => {
|
|
159
|
+
// this.error('unhandled rejection: %s', error.stack)
|
|
160
|
+
// })
|
|
161
|
+
/** System information.
|
|
162
|
+
* @type {SystemInfo}
|
|
163
|
+
* @readonly
|
|
164
|
+
*/
|
|
165
|
+
this.systemInfo = new homebridgeLib.SystemInfo()
|
|
166
|
+
this.systemInfo
|
|
167
|
+
.on('error', (error) => { this.warn(error) })
|
|
168
|
+
.on('exec', (command) => { this.debug('exec: %s', command) })
|
|
169
|
+
.on('readFile', (filename) => { this.debug('read file: %s', filename) })
|
|
170
|
+
await this.systemInfo.init()
|
|
171
|
+
this.log('hardware: %s', this.systemInfo.hwInfo.prettyName)
|
|
172
|
+
this.log('os: %s', this.systemInfo.osInfo.prettyName)
|
|
173
|
+
this.debug('starting heartbeat for %j', this.heartbeatClients)
|
|
174
|
+
this._heartbeatStart = new Date()
|
|
175
|
+
setTimeout(() => { this._beat(-1) }, 1000)
|
|
176
|
+
this.on('exit', () => {
|
|
177
|
+
this.debug('flush cachedAccessories')
|
|
178
|
+
this._homebridge.updatePlatformAccessories()
|
|
179
|
+
this.log('goodbye')
|
|
180
|
+
})
|
|
181
|
+
|
|
256
182
|
const n = Object.keys(this._accessories).length
|
|
257
183
|
if (n > 0) {
|
|
258
184
|
this.log('restored %d accessories from cache', n)
|
|
@@ -301,15 +227,11 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
301
227
|
this._homebridge.updatePlatformAccessories()
|
|
302
228
|
}
|
|
303
229
|
|
|
304
|
-
for (const plugin of this.heartbeatClients) {
|
|
305
|
-
global[globalKey][plugin].platform._heartbeat(beat)
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
_heartbeat (beat) {
|
|
310
230
|
if (beat % context.checkInterval === 0) {
|
|
311
|
-
this._checkLatest()
|
|
231
|
+
this._checkLatest(this._pluginName, this._pluginVersion)
|
|
232
|
+
this._checkLatest(context.libName, context.libVersion)
|
|
312
233
|
}
|
|
234
|
+
|
|
313
235
|
/** Emitted every second.
|
|
314
236
|
* @event Platform#heartbeat
|
|
315
237
|
* @param {number} beat - The sequence number of this heartbeat.
|
|
@@ -364,13 +286,10 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
364
286
|
|
|
365
287
|
// Issue an identity message.
|
|
366
288
|
_identify () {
|
|
367
|
-
const s = this._isHomebridgeLib
|
|
368
|
-
? ''
|
|
369
|
-
: ', ' + context.libName + ' v' + context.libVersion
|
|
370
289
|
this.log(
|
|
371
|
-
'%s v%s, node v%s, homebridge v%s%s',
|
|
372
|
-
this._pluginName, this._pluginVersion,
|
|
373
|
-
context.
|
|
290
|
+
'%s v%s, node v%s, homebridge v%s, %s v%s',
|
|
291
|
+
this._pluginName, this._pluginVersion, context.nodeVersion,
|
|
292
|
+
context.homebridgeVersion, context.libName, context.libVersion
|
|
374
293
|
)
|
|
375
294
|
if (context.nodeVersion !== context.recommendedNodeVersion) {
|
|
376
295
|
this.warn(
|
|
@@ -391,16 +310,16 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
391
310
|
}
|
|
392
311
|
|
|
393
312
|
// Check the NPM registry for the latest version of this plugin.
|
|
394
|
-
async _checkLatest () {
|
|
313
|
+
async _checkLatest (name, version) {
|
|
395
314
|
try {
|
|
396
|
-
if (
|
|
397
|
-
|
|
315
|
+
if (this.npmRegistry == null) {
|
|
316
|
+
this.npmRegistry = new homebridgeLib.HttpClient({
|
|
398
317
|
https: true,
|
|
399
318
|
host: 'registry.npmjs.org',
|
|
400
319
|
json: true,
|
|
401
320
|
maxSockets: 1
|
|
402
321
|
})
|
|
403
|
-
npmRegistry
|
|
322
|
+
this.npmRegistry
|
|
404
323
|
.on('error', (error) => {
|
|
405
324
|
this.log(
|
|
406
325
|
'npm registry: request %d: %s %s', error.request.id,
|
|
@@ -428,15 +347,14 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
428
347
|
response.statusCode, response.statusMessage
|
|
429
348
|
)
|
|
430
349
|
})
|
|
431
|
-
global[globalKey].Platform.npmRegistry = npmRegistry
|
|
432
350
|
}
|
|
433
|
-
const { body } = await
|
|
434
|
-
'/' +
|
|
351
|
+
const { body } = await this.npmRegistry.get(
|
|
352
|
+
'/' + name + '/latest', { Accept: 'application/json' })
|
|
435
353
|
if (body != null && body.version != null) {
|
|
436
|
-
if (body.version !==
|
|
437
|
-
this.warn('latest version: %s v%s',
|
|
354
|
+
if (body.version !== version) {
|
|
355
|
+
this.warn('latest version: %s v%s', name, body.version)
|
|
438
356
|
} else {
|
|
439
|
-
this.debug('latest version: %s v%s',
|
|
357
|
+
this.debug('latest version: %s v%s', name, body.version)
|
|
440
358
|
}
|
|
441
359
|
}
|
|
442
360
|
} catch (error) {
|
|
@@ -448,7 +366,16 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
448
366
|
|
|
449
367
|
// ===== Handle Accessories ==================================================
|
|
450
368
|
|
|
451
|
-
|
|
369
|
+
/** Configure an accessory, after it has been restored from peristent
|
|
370
|
+
* storage.
|
|
371
|
+
*
|
|
372
|
+
* Called by homebridge when restoring peristed accessories, typically from
|
|
373
|
+
* `~/.homebridge/accessories/cachedAccessories`.
|
|
374
|
+
* @method
|
|
375
|
+
* @param {!PlatformAccessory} accessory - The restored Homebridge
|
|
376
|
+
* [PlatformAccessory](https://github.com/nfarina/homebridge/blob/master/lib/platformAccessory.js).
|
|
377
|
+
*/
|
|
378
|
+
configureAccessory (accessory) {
|
|
452
379
|
const className = accessory.context.className
|
|
453
380
|
const version = accessory.context.version
|
|
454
381
|
const id = accessory.context.id
|
|
@@ -584,7 +511,7 @@ class Platform extends homebridgeLib.Delegate {
|
|
|
584
511
|
if (this._upnpMonitor != null) {
|
|
585
512
|
throw new SyntaxError('upnpConfig(): already called')
|
|
586
513
|
}
|
|
587
|
-
this._upnpMonitor = new
|
|
514
|
+
this._upnpMonitor = new homebridgeLib.UpnpClient(config)
|
|
588
515
|
this._upnpMonitor
|
|
589
516
|
.on('error', (error) => {
|
|
590
517
|
this.error('upnp: error')
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// homebridge-lib/lib/PropertyDelegate.js
|
|
2
|
+
//
|
|
3
|
+
// Library for Homebridge plugins.
|
|
4
|
+
// Copyright © 2017-2022 Erik Baauw. All rights reserved.
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const homebridgeLib = require('../index')
|
|
9
|
+
|
|
10
|
+
/** Delegate of a property of a delegate of a HomeKit accessory or HomeKit
|
|
11
|
+
* service.
|
|
12
|
+
*
|
|
13
|
+
* A property delegate manages a property value that:
|
|
14
|
+
* - Is persisted across homebridge restarts;
|
|
15
|
+
* - Can be monitored through homebridge's log output;
|
|
16
|
+
* - Can be monitored programmatically, through
|
|
17
|
+
* {@link PropertyDelegate#event:didSet didSet} events.
|
|
18
|
+
*
|
|
19
|
+
* @extends Delegate
|
|
20
|
+
*/
|
|
21
|
+
class PropertyDelegate extends homebridgeLib.Delegate {
|
|
22
|
+
/** Instantiate a property delegate.
|
|
23
|
+
*
|
|
24
|
+
* Note that instances are normally created by invoking
|
|
25
|
+
* {@link AccessoryDelegate#addPropertyDelegate addPropertyDelegate()} or
|
|
26
|
+
* {@link ServiceDelegate#addPropertyDelegate addPropertyDelegate()}.
|
|
27
|
+
* @param {!AccessoryDelegate|ServiceDelegate} delegate - Reference to the
|
|
28
|
+
* delegate of the corresponding HomeKit accessory or service.
|
|
29
|
+
* @param {!object} params - Parameters of the property delegate.
|
|
30
|
+
* @param {!string} params.key - The key for the property delegate.<br>
|
|
31
|
+
* Needs to be unique with parent delegate.
|
|
32
|
+
* @param {?boolean} params.silent - Suppress set log messages.
|
|
33
|
+
// * @param {!type} params.type - The type of the property value.
|
|
34
|
+
* @param {?*} params.value - The initial value of the property.<br>
|
|
35
|
+
* Only used when the property delegate is created for the first time.
|
|
36
|
+
* Otherwise, the value is restored from persistent storage.
|
|
37
|
+
* @param {?string} params.unit - The unit of the value of the property.
|
|
38
|
+
* @throws {TypeError} When a parameter has an invalid type.
|
|
39
|
+
* @throws {RangeError} When a parameter has an invalid value.
|
|
40
|
+
* @throws {SyntaxError} When a mandatory parameter is missing or an
|
|
41
|
+
* optional parameter is not applicable.
|
|
42
|
+
*/
|
|
43
|
+
constructor (parent, params = {}) {
|
|
44
|
+
if (!(
|
|
45
|
+
parent instanceof homebridgeLib.AccessoryDelegate ||
|
|
46
|
+
parent instanceof homebridgeLib.ServiceDelegate
|
|
47
|
+
)) {
|
|
48
|
+
throw new TypeError('parent: not an AccessoryDelegate')
|
|
49
|
+
}
|
|
50
|
+
super(parent.platform, parent.name + ': ' + params.key)
|
|
51
|
+
if (typeof params.key !== 'string') {
|
|
52
|
+
throw new TypeError('params.key: not a string')
|
|
53
|
+
}
|
|
54
|
+
this._parent = parent
|
|
55
|
+
this._key = params.key
|
|
56
|
+
this._log = params.silent ? this.debug : this.log
|
|
57
|
+
// this._type = params.type
|
|
58
|
+
this._unit = (params.unit != null) ? params.unit : ''
|
|
59
|
+
|
|
60
|
+
// Set initial value.
|
|
61
|
+
if (this.value == null && params.value != null) {
|
|
62
|
+
this.value = params.value
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.vdebug('created')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Destroy the propery delegate.
|
|
69
|
+
*/
|
|
70
|
+
_destroy () {
|
|
71
|
+
this.vdebug('destroy')
|
|
72
|
+
this.removeAllListeners()
|
|
73
|
+
delete this._parent._context[this.key]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Current log level (of the associated accessory or service delegate).
|
|
77
|
+
*
|
|
78
|
+
* The log level determines what type of messages are printed:
|
|
79
|
+
*
|
|
80
|
+
* 0. Print error and warning messages.
|
|
81
|
+
* 1. Print error, warning, and log messages.
|
|
82
|
+
* 2. Print error, warning, log, and debug messages.
|
|
83
|
+
* 3. Print error, warning, log, debug, and verbose debug messages.
|
|
84
|
+
*
|
|
85
|
+
* Note that debug messages (level 2 and 3) are only printed when
|
|
86
|
+
* Homebridge was started with the `-D` or `--debug` command line option.
|
|
87
|
+
*
|
|
88
|
+
* @type {!integer}
|
|
89
|
+
* @readonly
|
|
90
|
+
*/
|
|
91
|
+
get logLevel () {
|
|
92
|
+
return this._parent.logLevel
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
validate (value) {
|
|
96
|
+
// Todo: check value against type.
|
|
97
|
+
return { value: value, s: '' }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Value of associated Characteristic.
|
|
101
|
+
*/
|
|
102
|
+
get value () {
|
|
103
|
+
return this._parent._context[this._key]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
set value (v) {
|
|
107
|
+
const { value, s } = this.validate(v)
|
|
108
|
+
|
|
109
|
+
// Check for actual change.
|
|
110
|
+
if (value === this.value) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Issue info message that property value has been set.
|
|
115
|
+
if (this.value == null) {
|
|
116
|
+
this._log('set to %j%s%s', value, this._unit, s)
|
|
117
|
+
} else {
|
|
118
|
+
this._log(
|
|
119
|
+
'set to %j%s%s (from %j%s)', value, this._unit, s,
|
|
120
|
+
this.value, this._unit
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Update persisted value in ~/.homebridge/accessories/cachedAccessories.
|
|
125
|
+
this._parent._context[this._key] = value
|
|
126
|
+
|
|
127
|
+
/** Emitted when property value has changed.
|
|
128
|
+
* @event PropertyDelegate#didSet
|
|
129
|
+
* @param {*} value - The new property value.
|
|
130
|
+
*/
|
|
131
|
+
this.emit('didSet', value)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = PropertyDelegate
|
package/lib/ServiceDelegate.js
CHANGED
|
@@ -416,6 +416,22 @@ class AccessoryInformation extends ServiceDelegate {
|
|
|
416
416
|
})
|
|
417
417
|
}
|
|
418
418
|
}
|
|
419
|
+
|
|
420
|
+
addCharacteristicDelegate (params = {}) {
|
|
421
|
+
const delegate = super.addCharacteristicDelegate(params)
|
|
422
|
+
Object.defineProperty(this.accessoryDelegate.values, params.key, {
|
|
423
|
+
configurable: true, // make sure we can delete it again
|
|
424
|
+
writeable: true,
|
|
425
|
+
get () { return delegate.value },
|
|
426
|
+
set (value) { delegate.value = value }
|
|
427
|
+
})
|
|
428
|
+
return delegate
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
removeCharacteristicDelegate (key) {
|
|
432
|
+
delete this.accessoryDelegate.values[key]
|
|
433
|
+
super.removeCharacteristicDelegate(key)
|
|
434
|
+
}
|
|
419
435
|
}
|
|
420
436
|
|
|
421
437
|
/** Class for a _Battery_ service delegate.
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Library for homebridge plugins",
|
|
4
4
|
"author": "Erik Baauw",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"version": "5.
|
|
6
|
+
"version": "5.2.0",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"homekit",
|
|
9
9
|
"homebridge"
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"upnp": "cli/upnp.js"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
|
-
"homebridge": "^1.
|
|
25
|
-
"node": "^16.13.
|
|
24
|
+
"homebridge": "^1.4.0",
|
|
25
|
+
"node": "^16.13.2"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"bonjour-hap": "^3.6.3",
|