homebridge-lib 5.2.0 → 5.2.1

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.
@@ -1,1447 +0,0 @@
1
- // homebridge-lib/lib/ServiceDelegate.js
2
- //
3
- // Library for Homebridge plugins.
4
- // Copyright © 2017-2022 Erik Baauw. All rights reserved.
5
- //
6
- // The logic for handling Eve history was copied from Simone Tisa's
7
- // fakagato-history repository, copyright © 2017 simont77.
8
- // See https://github.com/simont77/fakegato-history.
9
-
10
- 'use strict'
11
-
12
- const homebridgeLib = require('../index')
13
-
14
- const util = require('util')
15
-
16
- /** Delegate of a HomeKit service.
17
- *
18
- * This delegate sets up a HomeKit service with the following HomeKit
19
- * characteristic:
20
- *
21
- * key | Characteristic
22
- * ---------------- | -----------------------------------
23
- * `name` | `Characteristics.hap.Name`
24
- * `configuredName` | `Characteristics.hap.ConfiguredName`
25
- * @abstract
26
- * @extends Delegate
27
- */
28
- class ServiceDelegate extends homebridgeLib.Delegate {
29
- /** Create a new instance of a HomeKit service delegate.
30
- *
31
- * When the associated HomeKit service was restored from persistent
32
- * storage, it is linked to the new delegate. Otherwise a new HomeKit
33
- * service will be created, using the values from `params`.
34
- * @param {!AccessoryDelegate} accessoryDelegate - Reference to the
35
- * associated HomeKit accessory delegate.
36
- * @param {!object} params - Properties of the HomeKit service.<br>
37
- * Next to the fixed properties below, `params` also contains the value for
38
- * each key specified in {@link ServiceDelegate#characteristics characteristics}.
39
- * @param {!string} params.name - The (Siri) name of the service.
40
- * Also used to prefix log and error messages.
41
- * @param {!Service} params.Service - The type of the HomeKit service.
42
- * @param {?string} params.subtype - The subtype of the HomeKit service.
43
- * Needs to be specified when the accessory has multuple services of the
44
- * same type.
45
- * @params {?boolean} params.primaryService - This is the primary service
46
- * for the accessory.
47
- * @params {?ServiceDelegate} params.linkedServiceDelegate - The delegate
48
- * of the service this service links to.
49
- * @params {?boolean} params.hidden - Hidden service.
50
- * @params {?boolean} params.exposeConfiguredName - Expose
51
- * `Characteristics.hap.ConfiguredName`, so device name can be synced with
52
- * HomeKit service name.
53
- */
54
- constructor (accessoryDelegate, params = {}) {
55
- if (!(accessoryDelegate instanceof homebridgeLib.AccessoryDelegate)) {
56
- throw new TypeError('parent: not a AccessoryDelegate')
57
- }
58
- if (params.name == null) {
59
- throw new SyntaxError('params.name: missing')
60
- }
61
- super(accessoryDelegate.platform, params.name)
62
- if (
63
- typeof params.Service !== 'function' ||
64
- typeof params.Service.UUID !== 'string'
65
- ) {
66
- throw new TypeError('params.Service: not a Service')
67
- }
68
- this._accessoryDelegate = accessoryDelegate
69
- this._accessory = this._accessoryDelegate._accessory
70
- this._key = params.Service.UUID
71
- if (params.subtype != null) {
72
- this._key += '.' + params.subtype
73
- }
74
-
75
- // Get or create associated Service.
76
- this._service = params.subtype == null
77
- ? this._accessory.getService(params.Service)
78
- : this._accessory.getServiceByUUIDAndSubType(params.Service, params.subtype)
79
- if (this._service == null) {
80
- this._service = this._accessory.addService(
81
- new params.Service(this.name, params.subtype)
82
- )
83
- this._service.displayName = this.name
84
- }
85
- this._accessoryDelegate._linkServiceDelegate(this)
86
- this._service.setPrimaryService(!!params.primaryService)
87
- if (params.linkedServiceDelegate != null) {
88
- params.linkedServiceDelegate._service.addLinkedService(this._service)
89
- }
90
- this._service.setHiddenService(!!params.hidden)
91
-
92
- // Fix bug in homebridge-lib@<4.3.0 that caused the service context in
93
- // ~/.homebridge/accessories/cachedAccessories to be stored under the
94
- // wrong key.
95
- if (
96
- params.subtype == null &&
97
- this._accessory.context[this._key + '.'] != null
98
- ) {
99
- this._accessory.context[this._key] =
100
- this._accessory.context[this._key + '.']
101
- delete this._accessory.context[this._key + '.']
102
- }
103
-
104
- // Setup persisted storage in ~/.homebridge/accessories/cachedAccessories.
105
- if (this._accessory.context[this._key] == null) {
106
- this._accessory.context[this._key] = {}
107
- }
108
- this._context = this._accessory.context[this._key]
109
-
110
- // Setup shortcut for characteristic values.
111
- this._values = {} // by key
112
-
113
- // Setup characteristics
114
- this._characteristicDelegates = {} // by key
115
- this._characteristics = {} // by uuid
116
-
117
- if (!params.hidden) {
118
- this.addCharacteristicDelegate({
119
- key: 'name',
120
- Characteristic: this.Characteristics.hap.Name,
121
- silent: true,
122
- value: params.name
123
- })
124
- if (params.exposeConfiguredName) {
125
- this.addCharacteristicDelegate({
126
- key: 'configuredName',
127
- Characteristic: this.Characteristics.hap.ConfiguredName,
128
- // silent: true,
129
- props: {
130
- perms: [
131
- this.Characteristic.Perms.READ, this.Characteristic.Perms.WRITE
132
- ]
133
- },
134
- value: params.name
135
- }).on('didSet', (value) => {
136
- if (value.trim() !== '') {
137
- this.name = value
138
- this._service.displayName = value
139
- this.values.name = value
140
- for (const key in this._characteristicDelegates) {
141
- this._characteristicDelegates[key].name = value
142
- }
143
- }
144
- })
145
- }
146
- }
147
-
148
- this.once('initialised', () => {
149
- const staleCharacteristics = []
150
- for (const uuid in this._service.characteristics) {
151
- const characteristic = this._service.characteristics[uuid]
152
- if (this._characteristics[characteristic.UUID] == null) {
153
- staleCharacteristics.push(characteristic)
154
- }
155
- }
156
- for (const characteristic of staleCharacteristics) {
157
- this.log('remove stale characteristic %s', characteristic.displayName)
158
- this._service.removeCharacteristic(characteristic)
159
- }
160
- const staleKeys = []
161
- for (const key in this._context) {
162
- if (key !== 'context' && this._characteristicDelegates[key] == null) {
163
- staleKeys.push(key)
164
- }
165
- }
166
- for (const key of staleKeys) {
167
- this.log('remove stale value %s', key)
168
- delete this._context[key]
169
- }
170
- })
171
- }
172
-
173
- /** Destroy the HomeKit service delegate.
174
- *
175
- * Destroys the associated HomeKit characteristic delegates.
176
- * Removes the associated HomeKit service.
177
- */
178
- destroy () {
179
- this.debug('destroy %s (%s)', this._key, this._service.displayName)
180
- this._accessoryDelegate._unlinkServiceDelegate(this)
181
- this.removeAllListeners()
182
- for (const key in this._characteristicDelegates) {
183
- this._characteristicDelegates[key]._destroy()
184
- }
185
- this._accessory.removeService(this._service)
186
- delete this._accessory.context[this._key]
187
- }
188
-
189
- /** Add a HomeKit characteristic delegate to the HomeKit service delegate.
190
- *
191
- * The characteristic delegate manages a value that:
192
- * - Is persisted across homebridge restarts;
193
- * - Can be monitored through homebridge's log output;
194
- * - Can be monitored programmatially through `didSet` events; and
195
- * - Mirrors the value of the optionally associated HomeKit characteristic.
196
- *
197
- * This value is accessed through {@link ServiceDelegate#values values}.
198
- * The delegate is returned, but can also be accessed through
199
- * {@link ServiceDelegate#characteristicDelegate characteristicDelegate()}.
200
- *
201
- * When the associated HomeKit characteristic was restored from persistent
202
- * storage, it is linked to the new delegate. Otherwise a new HomeKit
203
- * charactertistic will be created, using the values from `params`.
204
- * @param {!object} params - Properties of the HomeKit characteristic.
205
- * @param {!string} params.key - The key for the characteristic.
206
- * @param {?*} params.value - The initial value when the characteristic
207
- * is added.
208
- * @param {?boolean} params.silent - Suppress set log messages.
209
- * @param {?Characteristic} params.Characteristic - The type of the
210
- * characteristic, from {@link Delegate#Characteristic Characteristic}.
211
- * @param {?object} params.props - The properties of the HomeKit
212
- * characteristic.<br>
213
- * Overrides the properties from the characteristic type.
214
- * @param {?string} params.unit - The unit of the value of the HomeKit
215
- * characteristic.<br>
216
- * Overrides the unit from the characteristic type.
217
- * @param {?function} params.getter - Asynchronous function to be invoked
218
- * when HomeKit reads the characteristic value.<br>
219
- * This must be an `async` function returning a `Promise` to the new
220
- * characteristic value.
221
- * @param {?function} params.setter - Asynchronous function to be invoked
222
- * when HomeKit writes the characteristic value.<br>
223
- * This must be an `async` function returning a `Promise` that resolves
224
- * when the corresonding device value has been updated.
225
- * @returns {CharacteristicDelegate}
226
- * @throws {TypeError} When a parameter has an invalid type.
227
- * @throws {RangeError} When a parameter has an invalid value.
228
- * @throws {SyntaxError} When a mandatory parameter is missing or an
229
- * optional parameter is not applicable.
230
- */
231
- addCharacteristicDelegate (params = {}) {
232
- if (typeof params.key !== 'string') {
233
- throw new TypeError(`params.key: ${params.key}: invalid key`)
234
- }
235
- if (params.key === '') {
236
- throw new RangeError(`params.key: ${params.key}: invalid key`)
237
- }
238
- const key = params.key
239
- if (this.values[key] !== undefined) {
240
- throw new SyntaxError(`${key}: duplicate key`)
241
- }
242
-
243
- const characteristicDelegate = new homebridgeLib.CharacteristicDelegate(
244
- this, params
245
- )
246
- this._characteristicDelegates[key] = characteristicDelegate
247
- if (params.Characteristic != null) {
248
- this._characteristics[params.Characteristic.UUID] = true
249
- }
250
-
251
- // Create shortcut for characteristic value.
252
- Object.defineProperty(this.values, key, {
253
- configurable: true, // make sure we can delete it again
254
- writeable: true,
255
- get () { return characteristicDelegate.value },
256
- set (value) { characteristicDelegate.value = value }
257
- })
258
-
259
- return characteristicDelegate
260
- }
261
-
262
- removeCharacteristicDelegate (key) {
263
- delete this.values[key]
264
- const characteristicDelegate = this._characteristicDelegates[key]
265
- if (characteristicDelegate._characteristic != null) {
266
- const characteristic = characteristicDelegate._characteristic
267
- delete this._characteristics[characteristic.UUID]
268
- }
269
- characteristicDelegate._destroy()
270
- delete this._characteristicDelegates[key]
271
- delete this._context[key]
272
- }
273
-
274
- /** Values of the HomeKit characteristics for the HomeKit service.
275
- *
276
- * Contains the key of each characteristic added by
277
- * {@link ServiceDelegate#addCharacteristic addCharacteristic}.
278
- * When the value is written, the value of the corresponding HomeKit
279
- * characteristic is updated; when the characteristic value is changed from
280
- * HomeKit, this value is updated.
281
- * @type {object}
282
- */
283
- get values () {
284
- return this._values
285
- }
286
-
287
- /** Returns the HomeKit characteristic delegate correspondig to the key.
288
- * @param {!string} key - The key for the characteristic.
289
- * returns {CharacteristicDelegate}
290
- */
291
- characteristicDelegate (key) {
292
- return this._characteristicDelegates[key]
293
- }
294
-
295
- /** The corrresponding HomeKit accessory delegate.
296
- * @type {AccessoryDelegate}
297
- */
298
- get accessoryDelegate () {
299
- return this._accessoryDelegate
300
- }
301
-
302
- /** Service context to be persisted across Homebridge restarts.
303
- * @type {object}
304
- */
305
- get context () {
306
- if (this._context.context == null) {
307
- this._context.context = {}
308
- }
309
- return this._context.context
310
- }
311
-
312
- /** Current log level (of the associated accessory delegate).
313
- *
314
- * The log level determines what type of messages are printed:
315
- *
316
- * 0. Print error and warning messages.
317
- * 1. Print error, warning, and log messages.
318
- * 2. Print error, warning, log, and debug messages.
319
- * 3. Print error, warning, log, debug, and verbose debug messages.
320
- *
321
- * Note that debug messages (level 2 and 3) are only printed when
322
- * Homebridge was started with the `-D` or `--debug` command line option.
323
- *
324
- * @type {!integer}
325
- * @readonly
326
- */
327
- get logLevel () {
328
- return this._accessoryDelegate.logLevel
329
- }
330
-
331
- static get AccessoryInformation () { return AccessoryInformation }
332
- static get Battery () { return Battery }
333
- static get ServiceLabel () { return ServiceLabel }
334
- static get Dummy () { return Dummy }
335
- static get History () { return History }
336
- }
337
-
338
- /** Class for an _AccessoryInformation_ service delegate.
339
- *
340
- * This delegate sets up a `Services.hap.AccessoryInformation` HomeKit service
341
- * with the following HomeKit characteristics:
342
- *
343
- * key | Characteristic | isOptional
344
- * -------------- | -------------------------------------- | ----------
345
- * `name` | `Characteristics.hap.Name` |
346
- * `id` | `Characteristics.hap.SerialNumber` |
347
- * `manufacturer` | `Characteristics.hap.Manufacturer` |
348
- * `model` | `Characteristics.hap.Model` |
349
- * `firmware` | `Characteristics.hap.FirmwareRevision` |
350
- * `hardware` | `Characteristics.hap.HardwareRevision` | Y
351
- * `software` | `Characteristics.hap.SoftwareRevision` | Y
352
- * @extends ServiceDelegate
353
- * @memberof ServiceDelegate
354
- */
355
- class AccessoryInformation extends ServiceDelegate {
356
- /** Create a new instance of an _AccessoryInformation_ service delegate.
357
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
358
- * corresponding HomeKit accessory.
359
- * @param {!object} params - The parameters for the
360
- * _AccessoryInformation_ HomeKit service.
361
- * @param {!string} params.name - Initial value for
362
- * `Characteristics.hap.Name`. Also used to prefix log and error messages.
363
- * @param {!string} params.id - Initial value for
364
- * `Characteristics.hap.SerialNumber`.
365
- * @param {!string} params.manufacturer - Initial value for
366
- * `Characteristics.hap.Manufacturer`.
367
- * @param {!string} params.model - Initial value for
368
- * `Characteristics.hap.Model`.
369
- * @param {!string} params.firmware - Initial value for
370
- * `Characteristics.hap.FirmwareRevision`.
371
- * @param {?string} params.hardware - Initial value for
372
- * `Characteristics.hap.HardwareRevision`.
373
- * @param {?string} params.software - Initial value for
374
- * `Characteristics.hap.SoftwareRevision`.
375
- */
376
- constructor (accessoryDelegate, params = {}) {
377
- params.name = accessoryDelegate.name
378
- params.Service = accessoryDelegate.Services.hap.AccessoryInformation
379
- super(accessoryDelegate, params)
380
- this.addCharacteristicDelegate({
381
- key: 'id',
382
- Characteristic: this.Characteristics.hap.SerialNumber,
383
- value: params.id
384
- })
385
- this.addCharacteristicDelegate({
386
- key: 'identify',
387
- Characteristic: this.Characteristics.hap.Identify
388
- })
389
- this.addCharacteristicDelegate({
390
- key: 'manufacturer',
391
- Characteristic: this.Characteristics.hap.Manufacturer,
392
- value: params.manufacturer
393
- })
394
- this.addCharacteristicDelegate({
395
- key: 'model',
396
- Characteristic: this.Characteristics.hap.Model,
397
- value: params.model
398
- })
399
- this.addCharacteristicDelegate({
400
- key: 'firmware',
401
- Characteristic: this.Characteristics.hap.FirmwareRevision,
402
- value: params.firmware
403
- })
404
- if (params.hardware != null || this._context.hardware != null) {
405
- this.addCharacteristicDelegate({
406
- key: 'hardware',
407
- Characteristic: this.Characteristics.hap.HardwareRevision,
408
- value: params.hardware
409
- })
410
- }
411
- if (params.software != null || this._context.software != null) {
412
- this.addCharacteristicDelegate({
413
- key: 'software',
414
- Characteristic: this.Characteristics.hap.SoftwareRevision,
415
- value: params.software
416
- })
417
- }
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
- }
435
- }
436
-
437
- /** Class for a _Battery_ service delegate.
438
- *
439
- * This delegate sets up a `Services.hap.Battery` HomeKit service
440
- * with the following HomeKit characteristics:
441
- *
442
- * key | Characteristic | isOptional
443
- * ------------------ | -------------------------------------- | ----------
444
- * `name` | `Characteristics.hap.Name` |
445
- * `batteryLevel` | `Characteristics.hap.BatteryLevel` | Y
446
- * `chargingState` | `Characteristics.hap.ChargingState` | Y
447
- * `statusLowBattery` | `Characteristics.hap.StatusLowBattery` | Y
448
- * `lowBatteryThreshold`| `Characteristics.my.LowBatteryThreshold` | Y
449
- *
450
- * @extends ServiceDelegate
451
- * @memberof ServiceDelegate
452
- */
453
- class Battery extends ServiceDelegate {
454
- /** Create a new instance of an _Battery_ service delegate.
455
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
456
- * corresponding HomeKit accessory.
457
- * @param {object} params - The parameters for the
458
- * _AccessoryInformation_ HomeKit service.
459
- * @param {integer} [params.batteryLevel=100] - Initial value for
460
- * `Characteristics.hap.BatteryLevel`.
461
- * @param {integer} [params.chargingState=NOT_CHARGEABLE] - Initial value for
462
- * `Characteristics.hap.ChargingState`.
463
- * @param {integer} [params.statusLowBattery=BATTERY_LEVEL_NORMAL] - Initial
464
- * value for `Characteristics.hap.StatusLowBattery`.
465
- * @param {integer} [params.lowBatteryThreshold=20] - Initial value for
466
- * low battery threshold.
467
- */
468
- constructor (accessoryDelegate, params = {}) {
469
- params.name = accessoryDelegate.name + ' Battery'
470
- params.Service = accessoryDelegate.Services.hap.BatteryService
471
- super(accessoryDelegate, params)
472
- this.addCharacteristicDelegate({
473
- key: 'batteryLevel',
474
- Characteristic: this.Characteristics.hap.BatteryLevel,
475
- unit: '%',
476
- value: params.batteryLevel != null ? params.batteryLevel : 100
477
- }).on('didSet', (value) => {
478
- this.updateStatusLowBattery()
479
- })
480
- this.addCharacteristicDelegate({
481
- key: 'chargingState',
482
- Characteristic: this.Characteristics.hap.ChargingState,
483
- value: params.chargingState != null
484
- ? params.chargingState
485
- : this.Characteristics.hap.ChargingState.NOT_CHARGEABLE
486
- })
487
- this.addCharacteristicDelegate({
488
- key: 'statusLowBattery',
489
- Characteristic: this.Characteristics.hap.StatusLowBattery,
490
- value: params.statusLowBattery != null
491
- ? params.statusLowBattery
492
- : this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
493
- })
494
- this.addCharacteristicDelegate({
495
- key: 'lowBatteryThreshold',
496
- Characteristic: this.Characteristics.my.LowBatteryThreshold,
497
- unit: '%',
498
- value: params.lowBatteryThreshold != null ? params.lowBatteryThreshold : 20
499
- }).on('didSet', (value) => {
500
- this.updateStatusLowBattery()
501
- })
502
- }
503
-
504
- updateStatusLowBattery () {
505
- this.values.statusLowBattery =
506
- this.values.batteryLevel <= this.values.lowBatteryThreshold
507
- ? this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_LOW
508
- : this.Characteristics.hap.StatusLowBattery.BATTERY_LEVEL_NORMAL
509
- }
510
- }
511
-
512
- /** Class for a _ServiceLabel_ service delegate.
513
- *
514
- * This delegate sets up a `Services.hap.ServiceLabel` HomeKit service
515
- * with the following HomeKit characteristics:
516
- *
517
- * key | Characteristic | isOptional
518
- * -------------- | ------------------------------------------- | ----------
519
- * `name` | `Characteristics.hap.Name` |
520
- * `namespace` | `Characteristics.hap.ServiceLabelNamespace` |
521
- * @extends ServiceDelegate
522
- * @memberof ServiceDelegate
523
- */
524
- class ServiceLabel extends ServiceDelegate {
525
- /** Create a new instance of an _ServiceLabel_ service delegate.
526
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
527
- * corresponding HomeKit accessory.
528
- * @param {!object} params - The parameters for the
529
- * _AccessoryInformation_ HomeKit service.
530
- * @param {!string} params.name - Initial value for
531
- * `Characteristics.hap.Name`. Also used to prefix log and error messages.
532
- * @param {!string} params.namespace - Initial value for
533
- * `Characteristics.hap.ServiceLabelNamespace`.
534
- */
535
- constructor (accessoryDelegate, params = {}) {
536
- params.name = accessoryDelegate.name
537
- params.Service = accessoryDelegate.Services.hap.ServiceLabel
538
- super(accessoryDelegate, params)
539
- this.addCharacteristicDelegate({
540
- key: 'namespace',
541
- Characteristic: this.Characteristics.hap.ServiceLabelNamespace,
542
- value: params.namespace
543
- })
544
- }
545
- }
546
-
547
- /** Class for a delegate for a dummy _StatelessProgrammableSwitch_ service.
548
- *
549
- * This delegate sets up a dummy `Services.hap.StatelessProgrammableSwitch`
550
- * HomeKit service with the following HomeKit characteristics:
551
- *
552
- * key | Characteristic | isOptional
553
- * ------------------------- | --------------------------------------------- | ----------
554
- * `name` | `Characteristics.hap.Name` |
555
- * `programmableSwitchEvent` | `Characteristics.hap.ProgrammableSwitchEvent` |
556
- *
557
- * Including the dummy service prevents Home from showing a _Not Supported_
558
- * tile, and causes Home on iOS14 to show the _Favorite_ setting.
559
- * @extends ServiceDelegate
560
- * @memberof ServiceDelegate
561
- */
562
- class Dummy extends ServiceDelegate {
563
- constructor (nbAccessory, params = {}) {
564
- params.name = nbAccessory.name
565
- params.Service = nbAccessory.Services.hap.StatelessProgrammableSwitch
566
- super(nbAccessory, params)
567
-
568
- this.addCharacteristicDelegate({
569
- key: 'programmableSwitchEvent',
570
- Characteristic: this.Characteristics.hap.ProgrammableSwitchEvent,
571
- props: {
572
- minValue: this.Characteristics.hap.ProgrammableSwitchEvent.SINGLE_PRESS,
573
- maxValue: this.Characteristics.hap.ProgrammableSwitchEvent.SINGLE_PRESS
574
- }
575
- })
576
- }
577
- }
578
-
579
- const epoch = Math.round(new Date('2001-01-01T00:00:00Z').valueOf() / 1000)
580
-
581
- function hexToBase64 (value) {
582
- if (value == null || typeof value !== 'string') {
583
- throw new TypeError('value: not a string')
584
- }
585
- return Buffer.from((value).replace(/[^0-9A-F]/ig, ''), 'hex')
586
- .toString('base64')
587
- }
588
-
589
- function base64ToHex (value) {
590
- if (value == null || typeof value !== 'string') {
591
- throw new TypeError('value: not a string')
592
- }
593
- return Buffer.from(value, 'base64').toString('hex')
594
- }
595
-
596
- function swap16 (value) {
597
- return ((value & 0xFF) << 8) | ((value >>> 8) & 0xFF)
598
- }
599
-
600
- function swap32 (value) {
601
- return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) |
602
- ((value >>> 8) & 0xFF00) | ((value >>> 24) & 0xFF)
603
- }
604
-
605
- function numToHex (value, length) {
606
- let s = Number(value >>> 0).toString(16)
607
- if (s.length % 2 !== 0) {
608
- s = '0' + s
609
- }
610
- if (length) {
611
- return ('0000000000000' + s).slice(-length)
612
- }
613
- return s
614
- }
615
-
616
- /** Abstract superclass for an Eve _History_ service delegate.
617
- *
618
- * This delegate sets up a `Services.eve.History` HomeKit service
619
- * with keys for the following HomeKit characteristics:
620
- *
621
- * key | Characteristic
622
- * ---------------- | ----------------------------------
623
- * `name` | `Characteristics.hap.Name`
624
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
625
- * `setTime` | `Characteristics.eve.SetTime`
626
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
627
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
628
- * @abstract
629
- * @extends ServiceDelegate
630
- * @memberof ServiceDelegate
631
- */
632
- class History extends ServiceDelegate {
633
- /** Create a new instance of an Eve _History_ service delegate.
634
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
635
- * corresponding HomeKit accessory.
636
- * @param {!object} params - The parameters for the
637
- * _History_ HomeKit service.
638
- */
639
- constructor (accessoryDelegate, params = {}) {
640
- params.name = accessoryDelegate.name + ' History'
641
- params.Service = accessoryDelegate.Services.eve.History
642
- params.hidden = true
643
- super(accessoryDelegate, params)
644
- this._memorySize = 4032
645
- this._transfer = false
646
- this._restarted = true
647
-
648
- this.addCharacteristicDelegate({
649
- key: 'history',
650
- silent: true
651
- })
652
- if (this.context._history != null) {
653
- this.values.history = this.context._history
654
- delete this.context._history
655
- }
656
- this._h = this.values.history
657
- if (this._h == null) {
658
- this.values.history = {
659
- firstEntry: 0,
660
- lastEntry: 0,
661
- history: ['noValue'],
662
- usedMemory: 0,
663
- currentEntry: 1,
664
- initialTime: 0
665
- }
666
- this._h = this.values.history
667
- } else {
668
- this.debug('restored %d history entries', this._h.usedMemory)
669
- }
670
- if (this._h.refTime != null) {
671
- this._h.initialTime = this._h.refTime + epoch
672
- delete this._h.refTime
673
- }
674
-
675
- this.addCharacteristicDelegate({
676
- key: 'historyRequest',
677
- Characteristic: this.Characteristics.eve.HistoryRequest,
678
- value: params.historyRequest,
679
- setter: this._onSetHistoryRequest.bind(this),
680
- silent: true
681
- })
682
- this.addCharacteristicDelegate({
683
- key: 'setTime',
684
- Characteristic: this.Characteristics.eve.SetTime,
685
- value: params.setTime,
686
- silent: true
687
- })
688
- this.addCharacteristicDelegate({
689
- key: 'historyStatus',
690
- Characteristic: this.Characteristics.eve.HistoryStatus,
691
- value: params.historyStatus,
692
- silent: true
693
- })
694
- this.addCharacteristicDelegate({
695
- key: 'historyEntries',
696
- Characteristic: this.Characteristics.eve.HistoryEntries,
697
- value: params.historyEntries,
698
- getter: this._onGetEntries.bind(this),
699
- silent: true
700
- })
701
- this._accessoryDelegate.heartbeatEnabled = true
702
- this._accessoryDelegate
703
- .once('heartbeat', (beat) => {
704
- this._historyBeat = (beat % 600) + 5
705
- })
706
- .on('heartbeat', this._heartbeat.bind(this))
707
- .on('shutdown', () => {
708
- this.debug('saved %d history entries', this._h.usedMemory)
709
- })
710
- }
711
-
712
- _addEntry (now = Math.round(new Date().valueOf() / 1000)) {
713
- this._entry.time = now
714
- if (this._h.usedMemory < this._memorySize) {
715
- this._h.usedMemory++
716
- this._h.firstEntry = 0
717
- this._h.lastEntry = this._h.usedMemory
718
- } else {
719
- this._h.firstEntry++
720
- this._h.lastEntry = this._h.firstEntry + this._h.usedMemory
721
- if (this._restarted === true) {
722
- this._h.history[this._h.lastEntry % this._memorySize] = {
723
- time: this._entry.time,
724
- setRefTime: 1
725
- }
726
- this._h.firstEntry++
727
- this._h.lastEntry = this._h.firstEntry + this._h.usedMemory
728
- this._restarted = false
729
- }
730
- }
731
-
732
- if (this._h.initialTime === 0) {
733
- this._h.history[this._h.lastEntry] = {
734
- time: this._entry.time,
735
- setRefTime: 1
736
- }
737
- this._h.initialTime = this._entry.time
738
- this._h.lastEntry++
739
- this._h.usedMemory++
740
- }
741
-
742
- this._h.history[this._h.lastEntry % this._memorySize] =
743
- Object.assign({}, this._entry)
744
-
745
- const usedMemeoryOffset = this._h.usedMemory < this._memorySize ? 1 : 0
746
- const firstEntryOffset = this._h.usedMemory < this._memorySize ? 0 : 1
747
- const value = util.format(
748
- '%s 00000000 %s [%s] %s %s %s 000000000101',
749
- numToHex(swap32(this._entry.time - this._h.initialTime), 8),
750
- numToHex(swap32(this._h.initialTime - epoch), 8),
751
- this._fingerPrint,
752
- numToHex(swap16(this._h.usedMemory + usedMemeoryOffset), 4),
753
- numToHex(swap16(this._memorySize), 4),
754
- numToHex(swap32(this._h.firstEntry + firstEntryOffset), 8)
755
- )
756
-
757
- this.debug('add entry %d: %j', this._h.lastEntry, this._entry)
758
- this.debug('set history status to: %s', value)
759
- this.values.historyStatus = hexToBase64(value)
760
- }
761
-
762
- _heartbeat (beat) {
763
- if (beat % 600 === this._historyBeat) {
764
- this._addEntry()
765
- }
766
- }
767
-
768
- async _onSetHistoryRequest (value) {
769
- const entry = swap32(parseInt(base64ToHex(value).substring(4, 12), 16))
770
- this.debug('request entry: %d', entry)
771
- if (entry !== 0) {
772
- this._h.currentEntry = entry
773
- } else {
774
- this._h.currentEntry = 1
775
- }
776
- this._transfer = true
777
- }
778
-
779
- async _onGetEntries () {
780
- if (this._h.currentEntry > this._h.lastEntry || !this._transfer) {
781
- this.debug('send data: 00')
782
- this._transfer = false
783
- return hexToBase64('00')
784
- }
785
-
786
- let dataStream = ''
787
- for (let i = 0; i < 11; i++) {
788
- const address = this._h.currentEntry % this._memorySize
789
- if (
790
- this._h.history[address].setRefTime === 1 ||
791
- this._h.currentEntry === this._h.firstEntry + 1
792
- ) {
793
- this.debug(
794
- 'entry: %s, address %s, reftime: %s (%s)', this._h.currentEntry,
795
- address, this._h.initialTime - epoch,
796
- new Date(1000 * this._h.initialTime).toString().slice(0, 24)
797
- )
798
- dataStream += util.format(
799
- '|15 %s 0100000081 %s 00000000000000',
800
- numToHex(swap32(this._h.currentEntry), 8),
801
- numToHex(swap32(this._h.initialTime - epoch), 8))
802
- } else {
803
- this.debug(
804
- 'entry: %s, address: %s, time: %s (%s)', this._h.currentEntry,
805
- address, this._h.history[address].time - this._h.initialTime,
806
- new Date(1000 * this._h.history[address].time).toString().slice(0, 24)
807
- )
808
- dataStream += this._entryStream(this._h.history[address])
809
- }
810
- this._h.currentEntry++
811
- if (this._h.currentEntry > this._h.lastEntry) {
812
- break
813
- }
814
- }
815
- this.debug('send data: %s', dataStream)
816
- return hexToBase64(dataStream)
817
- }
818
-
819
- static get Consumption () { return Consumption }
820
-
821
- static get Contact () { return Contact }
822
-
823
- static get Motion () { return Motion }
824
-
825
- static get On () { return On }
826
-
827
- static get Power () { return Power }
828
-
829
- static get Thermo () { return Thermo }
830
-
831
- static get Weather () { return Weather }
832
- }
833
-
834
- /** Class for an Eve Energy _History_ service delegate.
835
- *
836
- * This delegate sets up a `Services.eve.History` HomeKit service
837
- * with keys for the following HomeKit characteristics:
838
- *
839
- * key | Characteristic
840
- * ---------------- | ----------------------------------
841
- * `name` | `Characteristics.hap.Name`
842
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
843
- * `setTime` | `Characteristics.eve.SetTime`
844
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
845
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
846
- *
847
- * This delegate is for sensors that report life-time consumption. The history
848
- * is computed from the changes to the value of the associated
849
- * `Characteristics.eve.TotalConsumption` characteristic. If the sensor doesn't
850
- * also report power, this delegate can update the the value of the associated
851
- * `Characteristics.eve.CurrentConsumption` characteristic.
852
- *
853
- * Note that the key in the history entry is called `power`, but its value
854
- * is the consumption in Wh since the previous entry.
855
- *
856
- * @extends ServiceDelegate.History
857
- * @memberof ServiceDelegate.History
858
- */
859
- class Consumption extends ServiceDelegate.History {
860
- /** Create a new instance of an Eve Energy _History_ service delegate.
861
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
862
- * corresponding HomeKit accessory.
863
- * @param {!object} params - The parameters for the
864
- * _History_ HomeKit service.
865
- * @param {!CharacteristicDelegate} consumptionDelegate - A reference to the
866
- * delegate of the associated `Characteristics.eve.TotalConsumption`
867
- * characteristic.
868
- * @param {?CharacteristicDelegate} powerDelegate - A reference to the
869
- * delegate of the associated `Characteristics.eve.CurrentConsumption`
870
- * characteristic.
871
- */
872
- constructor (
873
- accessoryDelegate, params, consumptionDelegate, powerDelegate
874
- ) {
875
- super(accessoryDelegate, params)
876
- if (!(consumptionDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
877
- throw new TypeError('consumptionDelegate: not a CharacteristicDelegate')
878
- }
879
- if (
880
- powerDelegate != null &&
881
- !(powerDelegate instanceof homebridgeLib.CharacteristicDelegate)
882
- ) {
883
- throw new TypeError('powerDelegate: not a CharacteristicDelegate')
884
- }
885
- this.addCharacteristicDelegate({
886
- key: 'consumption',
887
- silent: true
888
- })
889
- this.addCharacteristicDelegate({
890
- key: 'time',
891
- silent: true
892
- })
893
- this._consumptionDelegate = consumptionDelegate
894
- this._powerDelegate = powerDelegate
895
- this._entry = { time: 0, power: 0 }
896
- }
897
-
898
- _addEntry () {
899
- const now = Math.round(new Date().valueOf() / 1000)
900
- // Sensor deliveres totalConsumption, optionally compute currentConsumption
901
- if (this.values.consumption != null && this.values.time != null) {
902
- const delta = this._consumptionDelegate.value - this.values.consumption // kWh
903
- const period = now - this.values.time // s
904
- const power = Math.round(1000 * 3600 * delta / period) // W
905
- if (this._powerDelegate != null) {
906
- this._powerDelegate.value = power
907
- }
908
- this._entry.power = power
909
- super._addEntry(now)
910
- }
911
- this.values.consumption = this._consumptionDelegate.value
912
- this.values.time = now
913
- }
914
-
915
- // get _fingerPrint () { return '04 0102 0202 0702 0f03' }
916
- get _fingerPrint () { return '01 0702' }
917
-
918
- _entryStream (entry) {
919
- return util.format(
920
- // '|14 %s %s 1f 0000 0000 %s 0000 0000',
921
- '|0c %s %s 01 %s',
922
- numToHex(swap32(this._h.currentEntry), 8),
923
- numToHex(swap32(entry.time - this._h.initialTime), 8),
924
- numToHex(swap16(entry.power * 10), 4)
925
- )
926
- }
927
- }
928
-
929
- /** Class for an Eve Door _History_ service delegate.
930
- *
931
- * This delegate sets up a `Services.eve.History` HomeKit service
932
- * with keys for the following HomeKit characteristics:
933
- *
934
- * key | Characteristic
935
- * ---------------- | ----------------------------------
936
- * `name` | `Characteristics.hap.Name`
937
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
938
- * `setTime` | `Characteristics.eve.SetTime`
939
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
940
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
941
- * `resetTotal` | `Characteristics.eve.ResetTotal`
942
- *
943
- * This delegate creates the history from the associated
944
- * `Characteristics.hap.ContactSensorState` characteristic. It updates the
945
- * values of the associated `Characteristics.eve.TimesOpened` and
946
- * `Characteristics.eve.LastActivation` characteristics.
947
- * @extends ServiceDelegate.History
948
- * @memberof ServiceDelegate.History
949
- */
950
- class Contact extends ServiceDelegate.History {
951
- /** Create a new instance of an Eve Door _History_ service delegate.
952
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
953
- * corresponding HomeKit accessory.
954
- * @param {!object} params - The parameters for the
955
- * _History_ HomeKit service.
956
- * @param {!CharacteristicDelegate} contactDelegate - A reference to the
957
- * delegate of the associated `Characteristics.hap.ContactSensorState`
958
- * characteristic.
959
- * @param {!CharacteristicDelegate} timesOpenedDelegate - A reference to the
960
- * delegate of the associated `Characteristics.eve.TimesOpened`
961
- * characteristic.
962
- * @param {!CharacteristicDelegate} lastActivationDelegate - A reference to the
963
- * delegate of the associated `Characteristics.eve.LastActivation`
964
- * characteristic.
965
- */
966
- constructor (
967
- accessoryDelegate, params,
968
- contactDelegate, timesOpenedDelegate, lastActivationDelegate
969
- ) {
970
- super(accessoryDelegate, params)
971
- if (!(contactDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
972
- throw new TypeError('contactDelegate: not a CharacteristicDelegate')
973
- }
974
- if (!(timesOpenedDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
975
- throw new TypeError('timesOpenedDelegate: not a CharacteristicDelegate')
976
- }
977
- if (!(lastActivationDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
978
- throw new TypeError('lastActivationDelegate: not a CharacteristicDelegate')
979
- }
980
- this._entry = { time: 0, status: contactDelegate.value }
981
- contactDelegate.on('didSet', (value) => {
982
- const now = Math.round(new Date().valueOf() / 1000)
983
- timesOpenedDelegate.value += value
984
- lastActivationDelegate.value = now - this._h.initialTime
985
- this._entry.status = value
986
- this._addEntry(now)
987
- })
988
- this.addCharacteristicDelegate({
989
- key: 'resetTotal',
990
- Characteristic: this.Characteristics.eve.ResetTotal,
991
- value: params.resetTotal
992
- })
993
- this._characteristicDelegates.resetTotal.on('didSet', (value) => {
994
- timesOpenedDelegate.value = 0
995
- })
996
- }
997
-
998
- get _fingerPrint () { return '01 0601' }
999
-
1000
- _entryStream (entry) {
1001
- return util.format(
1002
- '|0b %s %s 01 %s',
1003
- numToHex(swap32(this._h.currentEntry), 8),
1004
- numToHex(swap32(entry.time - this._h.initialTime), 8),
1005
- numToHex(entry.status, 2)
1006
- )
1007
- }
1008
- }
1009
-
1010
- /** Class for an Eve Motion _History_ service delegate.
1011
- *
1012
- * This delegate sets up a `Services.eve.History` HomeKit service
1013
- * with keys for the following HomeKit characteristics:
1014
- *
1015
- * key | Characteristic
1016
- * ---------------- | ----------------------------------
1017
- * `name` | `Characteristics.hap.Name`
1018
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
1019
- * `setTime` | `Characteristics.eve.SetTime`
1020
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
1021
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
1022
- * `resetTotal` | `Characteristics.eve.ResetTotal`
1023
- *
1024
- * This delegate creates the history from the associated
1025
- * `Characteristics.hap.MotionDetected` characteristic. It updates the
1026
- * value of the associated `Characteristics.eve.LastActivation` characteristic.
1027
- * @extends ServiceDelegate.History
1028
- * @memberof ServiceDelegate.History
1029
- */
1030
- class Motion extends ServiceDelegate.History {
1031
- /** Create a new instance of an Eve Motion _History_ service delegate.
1032
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
1033
- * corresponding HomeKit accessory.
1034
- * @param {!object} params - The parameters for the
1035
- * _History_ HomeKit service.
1036
- * @param {!CharacteristicDelegate} motionDelegate - A reference to the
1037
- * delegate of the associated `Characteristics.hap.MotionDetected`
1038
- * characteristic.
1039
- * @param {!CharacteristicDelegate} lastActivationDelegate - A reference to the
1040
- * delegate of the associated `Characteristics.eve.LastActivation`
1041
- * characteristic.
1042
- * @param {?CharacteristicDelegate} temperatureDelegate - A reference to the
1043
- * delegate of the associated `Characteristics.hap.CurrentTemperature`
1044
- * characteristic. For PIR sensors (like the Hue motion sensor) that report
1045
- * temperature in addition to motion.
1046
- */
1047
- constructor (
1048
- accessoryDelegate, params,
1049
- motionDelegate, lastActivationDelegate, temperatureDelegate
1050
- ) {
1051
- super(accessoryDelegate, params)
1052
- if (!(motionDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1053
- throw new TypeError('motionDelegate: not a CharacteristicDelegate')
1054
- }
1055
- if (!(lastActivationDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1056
- throw new TypeError('lastActivationDelegate: not a CharacteristicDelegate')
1057
- }
1058
- if (
1059
- temperatureDelegate != null &&
1060
- !(temperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)
1061
- ) {
1062
- throw new TypeError('temperatureDelegate: not a CharacteristicDelegate')
1063
- }
1064
- this._entry = { time: 0, status: motionDelegate.value }
1065
- motionDelegate.on('didSet', (value) => {
1066
- const now = Math.round(new Date().valueOf() / 1000)
1067
- lastActivationDelegate.value = now - this._h.initialTime
1068
- this._entry.status = value
1069
- if (this._entry.temp != null) {
1070
- const temp = this._entry.temp
1071
- this._entry.temp = null
1072
- this._addEntry(now)
1073
- this._entry.temp = temp
1074
- } else {
1075
- this._addEntry(now)
1076
- }
1077
- })
1078
- if (temperatureDelegate != null) {
1079
- this._entry.temp = temperatureDelegate.value
1080
- temperatureDelegate.on('didSet', (value) => {
1081
- this._entry.temp = value
1082
- })
1083
- }
1084
- }
1085
-
1086
- get _fingerPrint () {
1087
- if (this._entry.temp != null) {
1088
- return '02 1c01 0102'
1089
- }
1090
- return '01 1c01'
1091
- }
1092
-
1093
- _entryStream (entry) {
1094
- if (this._entry.temp != null) {
1095
- return util.format(
1096
- '|0d %s %s 03 %s %s',
1097
- numToHex(swap32(this._h.currentEntry), 8),
1098
- numToHex(swap32(entry.time - this._h.initialTime), 8),
1099
- numToHex(entry.status, 2),
1100
- numToHex(swap16(entry.temp * 100), 4)
1101
- )
1102
- }
1103
- return util.format(
1104
- '|0b %s %s 01 %s',
1105
- numToHex(swap32(this._h.currentEntry), 8),
1106
- numToHex(swap32(entry.time - this._h.initialTime), 8),
1107
- numToHex(entry.status, 2)
1108
- )
1109
- }
1110
- }
1111
-
1112
- /** Class for an Eve Energy _History_ service delegate.
1113
- *
1114
- * This delegate sets up a `Services.eve.History` HomeKit service
1115
- * with keys for the following HomeKit characteristics:
1116
- *
1117
- * key | Characteristic
1118
- * ---------------- | ----------------------------------
1119
- * `name` | `Characteristics.hap.Name`
1120
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
1121
- * `setTime` | `Characteristics.eve.SetTime`
1122
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
1123
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
1124
- * `resetTotal` | `Characteristics.eve.ResetTotal`
1125
- *
1126
- * This delegate is for sensors that don't report life-time consumption. The
1127
- * history from the value of the associated
1128
- * `Characteristics.eve.CurrentConsumption` over time. It updates the value of
1129
- * the associated `Characteristics.eve.TotalConsumption` characteristic.
1130
- * @extends ServiceDelegate.History
1131
- * @memberof ServiceDelegate.History
1132
- */
1133
- class Power extends ServiceDelegate.History {
1134
- /** Create a new instance of an Eve Energy _History_ service delegate.
1135
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
1136
- * corresponding HomeKit accessory.
1137
- * @param {!object} params - The parameters for the
1138
- * _History_ HomeKit service.
1139
- * @param {!CharacteristicDelegate} powerDelegate - A reference to the
1140
- * delegate of the associated `Characteristics.eve.CurrentConsumption`
1141
- * characteristic.
1142
- * @param {!CharacteristicDelegate} consumptionDelegate - A reference to the
1143
- * delegate of the associated `Characteristics.eve.TotalConsumption`
1144
- * characteristic.
1145
- */
1146
- constructor (
1147
- accessoryDelegate, params,
1148
- powerDelegate, consumptionDelegate
1149
- ) {
1150
- super(accessoryDelegate, params)
1151
- if (!(powerDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1152
- throw new TypeError('powerDelegate: not a CharacteristicDelegate')
1153
- }
1154
- if (!(consumptionDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1155
- throw new TypeError('consumptionDelegate: not a CharacteristicDelegate')
1156
- }
1157
- this._powerDelegate = powerDelegate
1158
- this._consumptionDelegate = consumptionDelegate
1159
- this._entry = { time: 0, power: 0 }
1160
- this._runningConsumption = 0 // 10-min-interval running value
1161
- this._totalConsumption = consumptionDelegate.value // life-time value
1162
- powerDelegate.on('didSet', (value) => {
1163
- const now = Math.round(new Date().valueOf() / 1000)
1164
- if (this._time != null) {
1165
- const delta = this._power * (now - this._time) // Ws
1166
- this._runningConsumption += Math.round(delta / 600.0) // W * 10 min
1167
- this._totalConsumption += Math.round(delta / 3600.0) // Wh
1168
- }
1169
- this._power = value
1170
- this._time = now
1171
- })
1172
- this.addCharacteristicDelegate({
1173
- key: 'resetTotal',
1174
- Characteristic: this.Characteristics.eve.ResetTotal,
1175
- value: params.resetTotal
1176
- })
1177
- this._characteristicDelegates.resetTotal.on('didSet', (value) => {
1178
- this._runningConsumption = 0
1179
- this._totalConsumption = 0
1180
- this._consumptionDelegate.value = this._totalConsumption
1181
- })
1182
- }
1183
-
1184
- _addEntry () {
1185
- // Sensor delivers currentConsumption, compute totalConsumption
1186
- const now = Math.round(new Date().valueOf() / 1000)
1187
- if (this._time != null) {
1188
- const delta = this._power * (now - this._time) // Ws
1189
- this._runningConsumption += Math.round(delta / 600.0) // W * 10 min
1190
- this._totalConsumption += Math.round(delta / 3600.0) // Wh
1191
- this._consumptionDelegate.value = this._totalConsumption
1192
- this._entry.power = this._runningConsumption
1193
- super._addEntry(now)
1194
- }
1195
- this._power = this._powerDelegate.value
1196
- this._time = now
1197
- this._runningConsumption = 0
1198
- }
1199
-
1200
- // get _fingerPrint () { return '04 0102 0202 0702 0f03' }
1201
- get _fingerPrint () { return '01 0702' }
1202
-
1203
- _entryStream (entry) {
1204
- return util.format(
1205
- // '|14 %s %s 1f 0000 0000 %s 0000 0000',
1206
- '|0c %s %s 01 %s',
1207
- numToHex(swap32(this._h.currentEntry), 8),
1208
- numToHex(swap32(entry.time - this._h.initialTime), 8),
1209
- numToHex(swap16(entry.power * 10), 4)
1210
- )
1211
- }
1212
- }
1213
-
1214
- /** Class for an Eve Thermo _History_ service delegate.
1215
- *
1216
- * This delegate sets up a `Services.eve.History` HomeKit service
1217
- * with keys for the following HomeKit characteristics:
1218
- *
1219
- * key | Characteristic
1220
- * ---------------- | ----------------------------------
1221
- * `name` | `Characteristics.hap.Name`
1222
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
1223
- * `setTime` | `Characteristics.eve.SetTime`
1224
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
1225
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
1226
- *
1227
- * This delegate creates the history from the associated
1228
- * `Characteristics.hap.CurrentTemperature`,
1229
- * `Characteristics.hap.TargetTemperature`, and
1230
- * `Characteristics.eve.ValvePosition` characteristics.
1231
- * @extends ServiceDelegate.History
1232
- * @memberof ServiceDelegate.History
1233
- */
1234
- class Thermo extends ServiceDelegate.History {
1235
- /** Create a new instance of an Eve Thermo _History_ service delegate.
1236
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
1237
- * corresponding HomeKit accessory.
1238
- * @param {!object} params - The parameters for the
1239
- * _History_ HomeKit service.
1240
- * @param {!CharacteristicDelegate} temperatureDelegate - A reference to the
1241
- * delegate of the associated `Characteristics.hap.CurrentTemperature`
1242
- * characteristic.
1243
- * @param {!CharacteristicDelegate} targetTemperatureDelegate - A reference
1244
- * to the delegate of the associated `Characteristics.hap.TargetTemperature`
1245
- * characteristic.
1246
- * @param {!CharacteristicDelegate} valvePositionDelegate - A reference to
1247
- * the delegate of the associated `Characteristics.eve.ValvePosition`
1248
- * characteristic.
1249
- */
1250
- constructor (
1251
- accessoryDelegate, params,
1252
- temperatureDelegate, targetTemperatureDelegate, valvePositionDelegate
1253
- ) {
1254
- super(accessoryDelegate, params)
1255
- if (!(temperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1256
- throw new TypeError('temperatureDelegate: not a CharacteristicDelegate')
1257
- }
1258
- if (!(targetTemperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1259
- throw new TypeError('targetTemperatureDelegate: not a CharacteristicDelegate')
1260
- }
1261
- if (!(valvePositionDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1262
- throw new TypeError('valvePositionDelegate: not a CharacteristicDelegate')
1263
- }
1264
- this._entry = {
1265
- time: 0,
1266
- currentTemp: temperatureDelegate.value,
1267
- setTemp: targetTemperatureDelegate.value,
1268
- valvePosition: valvePositionDelegate.value
1269
- }
1270
- temperatureDelegate
1271
- .on('didSet', (value) => { this._entry.currentTemp = value })
1272
- targetTemperatureDelegate
1273
- .on('didSet', (value) => { this._entry.setTemp = value })
1274
- valvePositionDelegate
1275
- .on('didSet', (value) => { this._entry.valvePosition = value })
1276
- }
1277
-
1278
- // I think 1201 and 1d01 are for current mode and target more, but it doesn't
1279
- // look like Eve displays any history for these.
1280
- // As of v3.8.1, Eve no longer shows the valve position history.
1281
- // get _fingerPrint () { return '05 0102 1102 1001 1201 1d01' }
1282
- get _fingerPrint () { return '03 0102 1102 1001' }
1283
-
1284
- _entryStream (entry) {
1285
- return util.format(
1286
- // '|11 %s %s 1f %s %s %s 00 00',
1287
- '|0f %s %s 07 %s %s %s',
1288
- numToHex(swap32(this._h.currentEntry), 8),
1289
- numToHex(swap32(entry.time - this._h.initialTime), 8),
1290
- numToHex(swap16(entry.currentTemp * 100), 4),
1291
- numToHex(swap16(entry.setTemp * 100), 4),
1292
- numToHex(entry.valvePosition, 2)
1293
- )
1294
- }
1295
- }
1296
-
1297
- /** Class for an Eve Weather _History_ service delegate.
1298
- *
1299
- * This delegate sets up a `Services.eve.History` HomeKit service
1300
- * with keys for the following HomeKit characteristics:
1301
- *
1302
- * key | Characteristic
1303
- * ---------------- | ----------------------------------
1304
- * `name` | `Characteristics.hap.Name`
1305
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
1306
- * `setTime` | `Characteristics.eve.SetTime`
1307
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
1308
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
1309
- *
1310
- * This delegate creates the history from the associated
1311
- * `Characteristics.hap.CurrentTemperature`,
1312
- * `Characteristics.hap.CurrentRelativeHumidity`, and
1313
- * `Characteristics.eve.AirPressure` characteristics.
1314
- * @extends ServiceDelegate.History
1315
- * @memberof ServiceDelegate.History
1316
- */
1317
- class Weather extends ServiceDelegate.History {
1318
- /** Create a new instance of an Eve Weather _History_ service delegate.
1319
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
1320
- * corresponding HomeKit accessory.
1321
- * @param {!object} params - The parameters for the
1322
- * _History_ HomeKit service.
1323
- * @param {!CharacteristicDelegate} temperatureDelegate - A reference to the
1324
- * delegate of the associated `Characteristics.hap.CurrentTemperature`
1325
- * characteristic.
1326
- * @param {?CharacteristicDelegate} humidityDelegate - A reference to the
1327
- * delegate of the associated `Characteristics.hap.CurrentRelativeHumidity`
1328
- * characteristic.
1329
- * @param {?CharacteristicDelegate} pressureDelegate - A reference to the
1330
- * delegate of the associated `Characteristics.eve.AirPressure`
1331
- * characteristic.
1332
- */
1333
- constructor (
1334
- accessoryDelegate, params,
1335
- temperatureDelegate, humidityDelegate, pressureDelegate
1336
- ) {
1337
- super(accessoryDelegate, params)
1338
- if (!(temperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1339
- throw new TypeError('temperatureDelegate: not a CharacteristicDelegate')
1340
- }
1341
- if (
1342
- humidityDelegate != null &&
1343
- !(humidityDelegate instanceof homebridgeLib.CharacteristicDelegate)
1344
- ) {
1345
- throw new TypeError('humidityDelegate: not a CharacteristicDelegate')
1346
- }
1347
- if (
1348
- pressureDelegate != null &&
1349
- !(pressureDelegate instanceof homebridgeLib.CharacteristicDelegate)
1350
- ) {
1351
- throw new TypeError('pressureDelegate: not a CharacteristicDelegate')
1352
- }
1353
- this._entry = {
1354
- time: 0,
1355
- temp: temperatureDelegate.value,
1356
- humidity: 0,
1357
- pressure: 0
1358
- }
1359
- temperatureDelegate.on('didSet', (value) => {
1360
- this._entry.temp = value
1361
- })
1362
- if (humidityDelegate != null) {
1363
- this._entry.humidity = humidityDelegate.value
1364
- humidityDelegate.on('didSet', (value) => {
1365
- this._entry.humidity = value
1366
- })
1367
- if (pressureDelegate != null) {
1368
- this._entry.pressure = pressureDelegate.value
1369
- pressureDelegate.on('didSet', (value) => {
1370
- this._entry.pressure = value
1371
- })
1372
- }
1373
- }
1374
- }
1375
-
1376
- get _fingerPrint () {
1377
- return '03 0102 0202 0302'
1378
- }
1379
-
1380
- _entryStream (entry) {
1381
- return util.format(
1382
- '|10 %s %s 07 %s %s %s',
1383
- numToHex(swap32(this._h.currentEntry), 8),
1384
- numToHex(swap32(entry.time - this._h.initialTime), 8),
1385
- numToHex(swap16(entry.temp * 100), 4),
1386
- numToHex(swap16(entry.humidity * 100), 4),
1387
- numToHex(swap16(entry.pressure * 10), 4)
1388
- )
1389
- }
1390
- }
1391
-
1392
- /** Class for a Raspberry Pi _History_ service delegate.
1393
- *
1394
- * This delegate sets up a `Services.eve.History` HomeKit service
1395
- * with keys for the following HomeKit characteristics:
1396
- *
1397
- * key | Characteristic
1398
- * ---------------- | ----------------------------------
1399
- * `name` | `Characteristics.hap.Name`
1400
- * `historyRequest` | `Characteristics.eve.HistoryRequest`
1401
- * `setTime` | `Characteristics.eve.SetTime`
1402
- * `historyStatus` | `Characteristics.eve.HistoryStatus`
1403
- * `historyEntries` | `Characteristics.eve.HistoryEntries`
1404
- *
1405
- * This delegate creates the history from the associated
1406
- * `Characteristics.hap.On` characteristic.
1407
- * @extends ServiceDelegate.History
1408
- * @memberof ServiceDelegate.History
1409
- */
1410
- class On extends ServiceDelegate.History {
1411
- /** Create a new instance of a Raspberry Pi _History_ service delegate.
1412
- * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
1413
- * corresponding HomeKit accessory.
1414
- * @param {!object} params - The parameters for the
1415
- * _History_ HomeKit service.
1416
- * @param {!CharacteristicDelegate} onDelegate - A reference to the
1417
- * delegate of the associated `Characteristics.hap.On`
1418
- * characteristic.
1419
- */
1420
- constructor (accessoryDelegate, params, onDelegate) {
1421
- super(accessoryDelegate, params)
1422
- if (!(onDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
1423
- throw new TypeError('onDelegate: not a CharacteristicDelegate')
1424
- }
1425
- this._entry = {
1426
- time: 0,
1427
- on: onDelegate.value ? 1 : 0
1428
- }
1429
- onDelegate.on('didSet', (value) => {
1430
- this._entry.on = value ? 1 : 0
1431
- this._addEntry()
1432
- })
1433
- }
1434
-
1435
- get _fingerPrint () { return '01 0e01' }
1436
-
1437
- _entryStream (entry) {
1438
- return util.format(
1439
- '|0b %s %s 01 %s',
1440
- numToHex(swap32(this._h.currentEntry), 8),
1441
- numToHex(swap32(entry.time - this._h.initialTime), 8),
1442
- numToHex(entry.on, 2)
1443
- )
1444
- }
1445
- }
1446
-
1447
- module.exports = ServiceDelegate