homebridge-lib 5.1.24-5 → 5.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/AccessoryDelegate.js +21 -23
- package/lib/AdaptiveLighting.js +8 -2
- package/lib/CharacteristicDelegate.js +11 -2
- package/lib/EveHomeKitTypes.js +7 -1
- package/lib/MyHomeKitTypes.js +2 -1
- package/lib/Platform.js +58 -132
- package/lib/ServiceDelegate/AccessoryInformation.js +111 -0
- package/lib/ServiceDelegate/Battery.js +87 -0
- package/lib/ServiceDelegate/Dummy.js +44 -0
- package/lib/ServiceDelegate/History/Consumption.js +114 -0
- package/lib/ServiceDelegate/History/Contact.js +100 -0
- package/lib/ServiceDelegate/History/Motion.js +122 -0
- package/lib/ServiceDelegate/History/On.js +86 -0
- package/lib/ServiceDelegate/History/Power.js +121 -0
- package/lib/ServiceDelegate/History/Room.js +115 -0
- package/lib/ServiceDelegate/History/Thermo.js +102 -0
- package/lib/ServiceDelegate/History/Weather.js +114 -0
- package/lib/ServiceDelegate/History/index.js +318 -0
- package/lib/ServiceDelegate/ServiceLabel.js +47 -0
- package/lib/ServiceDelegate/index.js +332 -0
- package/package.json +2 -2
- package/lib/ServiceDelegate.js +0 -1447
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// homebridge-lib/lib/ServiceDelegate/History/Room.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
|
+
const util = require('util')
|
|
14
|
+
|
|
15
|
+
const { ServiceDelegate } = homebridgeLib
|
|
16
|
+
const { History } = ServiceDelegate
|
|
17
|
+
const { swap16, swap32, numToHex } = History
|
|
18
|
+
|
|
19
|
+
/** Class for an Eve Room _History_ service delegate.
|
|
20
|
+
*
|
|
21
|
+
* This delegate sets up a `Services.eve.History` HomeKit service
|
|
22
|
+
* with keys for the following HomeKit characteristics:
|
|
23
|
+
*
|
|
24
|
+
* key | Characteristic
|
|
25
|
+
* ---------------- | ----------------------------------
|
|
26
|
+
* `name` | `Characteristics.hap.Name`
|
|
27
|
+
* `historyRequest` | `Characteristics.eve.HistoryRequest`
|
|
28
|
+
* `setTime` | `Characteristics.eve.SetTime`
|
|
29
|
+
* `historyStatus` | `Characteristics.eve.HistoryStatus`
|
|
30
|
+
* `historyEntries` | `Characteristics.eve.HistoryEntries`
|
|
31
|
+
*
|
|
32
|
+
* This delegate creates the history from the associated
|
|
33
|
+
* `Characteristics.hap.CurrentTemperature`,
|
|
34
|
+
* `Characteristics.hap.CurrentRelativeHumidity`, and
|
|
35
|
+
* `Characteristics.hap.VOCDensity` characteristics.
|
|
36
|
+
* @extends ServiceDelegate.History
|
|
37
|
+
* @memberof ServiceDelegate.History
|
|
38
|
+
*/
|
|
39
|
+
class Room extends ServiceDelegate.History {
|
|
40
|
+
/** Create a new instance of an Eve Weather _History_ service delegate.
|
|
41
|
+
* @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
|
|
42
|
+
* corresponding HomeKit accessory.
|
|
43
|
+
* @param {!object} params - The parameters for the
|
|
44
|
+
* _History_ HomeKit service.
|
|
45
|
+
* @param {!CharacteristicDelegate} temperatureDelegate - A reference to the
|
|
46
|
+
* delegate of the associated `Characteristics.hap.CurrentTemperature`
|
|
47
|
+
* characteristic.
|
|
48
|
+
* @param {?CharacteristicDelegate} humidityDelegate - A reference to the
|
|
49
|
+
* delegate of the associated `Characteristics.hap.CurrentRelativeHumidity`
|
|
50
|
+
* characteristic.
|
|
51
|
+
* @param {?CharacteristicDelegate} vocDensityDelegate - A reference to the
|
|
52
|
+
* delegate of the associated `Characteristics.eve.AirPressure`
|
|
53
|
+
* characteristic.
|
|
54
|
+
*/
|
|
55
|
+
constructor (
|
|
56
|
+
accessoryDelegate, params,
|
|
57
|
+
temperatureDelegate, humidityDelegate, vocDensityDelegate
|
|
58
|
+
) {
|
|
59
|
+
super(accessoryDelegate, params)
|
|
60
|
+
if (!(temperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
|
|
61
|
+
throw new TypeError('temperatureDelegate: not a CharacteristicDelegate')
|
|
62
|
+
}
|
|
63
|
+
if (
|
|
64
|
+
humidityDelegate != null &&
|
|
65
|
+
!(humidityDelegate instanceof homebridgeLib.CharacteristicDelegate)
|
|
66
|
+
) {
|
|
67
|
+
throw new TypeError('humidityDelegate: not a CharacteristicDelegate')
|
|
68
|
+
}
|
|
69
|
+
if (
|
|
70
|
+
vocDensityDelegate != null &&
|
|
71
|
+
!(vocDensityDelegate instanceof homebridgeLib.CharacteristicDelegate)
|
|
72
|
+
) {
|
|
73
|
+
throw new TypeError('vocDensityDelegate: not a CharacteristicDelegate')
|
|
74
|
+
}
|
|
75
|
+
this._entry = {
|
|
76
|
+
time: 0,
|
|
77
|
+
temp: temperatureDelegate.value,
|
|
78
|
+
humidity: 0,
|
|
79
|
+
voc: 0
|
|
80
|
+
}
|
|
81
|
+
temperatureDelegate.on('didSet', (value) => {
|
|
82
|
+
this._entry.temp = value
|
|
83
|
+
})
|
|
84
|
+
if (humidityDelegate != null) {
|
|
85
|
+
this._entry.humidity = humidityDelegate.value
|
|
86
|
+
humidityDelegate.on('didSet', (value) => {
|
|
87
|
+
this._entry.humidity = value
|
|
88
|
+
})
|
|
89
|
+
if (vocDensityDelegate != null) {
|
|
90
|
+
this._entry.voc = vocDensityDelegate.value
|
|
91
|
+
vocDensityDelegate.on('didSet', (value) => {
|
|
92
|
+
this._entry.voc = value
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get _fingerPrint () {
|
|
99
|
+
// return '07 0102 0202 2202 2901 2501 2302 2801'
|
|
100
|
+
return '03 0102 0202 2202'
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_entryStream (entry) {
|
|
104
|
+
return util.format(
|
|
105
|
+
'|10 %s %s 07 %s %s %s',
|
|
106
|
+
numToHex(swap32(this._h.currentEntry), 8),
|
|
107
|
+
numToHex(swap32(entry.time - this._h.initialTime), 8),
|
|
108
|
+
numToHex(swap16(entry.temp * 100), 4),
|
|
109
|
+
numToHex(swap16(entry.humidity * 100), 4),
|
|
110
|
+
numToHex(swap16(entry.voc), 4)
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = Room
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// homebridge-lib/lib/ServiceDelegate/History/Thermo.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
|
+
const util = require('util')
|
|
14
|
+
|
|
15
|
+
const { ServiceDelegate } = homebridgeLib
|
|
16
|
+
const { History } = ServiceDelegate
|
|
17
|
+
const { swap16, swap32, numToHex } = History
|
|
18
|
+
|
|
19
|
+
/** Class for an Eve Thermo _History_ service delegate.
|
|
20
|
+
*
|
|
21
|
+
* This delegate sets up a `Services.eve.History` HomeKit service
|
|
22
|
+
* with keys for the following HomeKit characteristics:
|
|
23
|
+
*
|
|
24
|
+
* key | Characteristic
|
|
25
|
+
* ---------------- | ----------------------------------
|
|
26
|
+
* `name` | `Characteristics.hap.Name`
|
|
27
|
+
* `historyRequest` | `Characteristics.eve.HistoryRequest`
|
|
28
|
+
* `setTime` | `Characteristics.eve.SetTime`
|
|
29
|
+
* `historyStatus` | `Characteristics.eve.HistoryStatus`
|
|
30
|
+
* `historyEntries` | `Characteristics.eve.HistoryEntries`
|
|
31
|
+
*
|
|
32
|
+
* This delegate creates the history from the associated
|
|
33
|
+
* `Characteristics.hap.CurrentTemperature`,
|
|
34
|
+
* `Characteristics.hap.TargetTemperature`, and
|
|
35
|
+
* `Characteristics.eve.ValvePosition` characteristics.
|
|
36
|
+
* @extends ServiceDelegate.History
|
|
37
|
+
* @memberof ServiceDelegate.History
|
|
38
|
+
*/
|
|
39
|
+
class Thermo extends ServiceDelegate.History {
|
|
40
|
+
/** Create a new instance of an Eve Thermo _History_ service delegate.
|
|
41
|
+
* @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
|
|
42
|
+
* corresponding HomeKit accessory.
|
|
43
|
+
* @param {!object} params - The parameters for the
|
|
44
|
+
* _History_ HomeKit service.
|
|
45
|
+
* @param {!CharacteristicDelegate} temperatureDelegate - A reference to the
|
|
46
|
+
* delegate of the associated `Characteristics.hap.CurrentTemperature`
|
|
47
|
+
* characteristic.
|
|
48
|
+
* @param {!CharacteristicDelegate} targetTemperatureDelegate - A reference
|
|
49
|
+
* to the delegate of the associated `Characteristics.hap.TargetTemperature`
|
|
50
|
+
* characteristic.
|
|
51
|
+
* @param {!CharacteristicDelegate} valvePositionDelegate - A reference to
|
|
52
|
+
* the delegate of the associated `Characteristics.eve.ValvePosition`
|
|
53
|
+
* characteristic.
|
|
54
|
+
*/
|
|
55
|
+
constructor (
|
|
56
|
+
accessoryDelegate, params,
|
|
57
|
+
temperatureDelegate, targetTemperatureDelegate, valvePositionDelegate
|
|
58
|
+
) {
|
|
59
|
+
super(accessoryDelegate, params)
|
|
60
|
+
if (!(temperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
|
|
61
|
+
throw new TypeError('temperatureDelegate: not a CharacteristicDelegate')
|
|
62
|
+
}
|
|
63
|
+
if (!(targetTemperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
|
|
64
|
+
throw new TypeError('targetTemperatureDelegate: not a CharacteristicDelegate')
|
|
65
|
+
}
|
|
66
|
+
if (!(valvePositionDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
|
|
67
|
+
throw new TypeError('valvePositionDelegate: not a CharacteristicDelegate')
|
|
68
|
+
}
|
|
69
|
+
this._entry = {
|
|
70
|
+
time: 0,
|
|
71
|
+
currentTemp: temperatureDelegate.value,
|
|
72
|
+
setTemp: targetTemperatureDelegate.value,
|
|
73
|
+
valvePosition: valvePositionDelegate.value
|
|
74
|
+
}
|
|
75
|
+
temperatureDelegate
|
|
76
|
+
.on('didSet', (value) => { this._entry.currentTemp = value })
|
|
77
|
+
targetTemperatureDelegate
|
|
78
|
+
.on('didSet', (value) => { this._entry.setTemp = value })
|
|
79
|
+
valvePositionDelegate
|
|
80
|
+
.on('didSet', (value) => { this._entry.valvePosition = value })
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// I think 1201 and 1d01 are for current mode and target more, but it doesn't
|
|
84
|
+
// look like Eve displays any history for these.
|
|
85
|
+
// As of v3.8.1, Eve no longer shows the valve position history.
|
|
86
|
+
// get _fingerPrint () { return '05 0102 1102 1001 1201 1d01' }
|
|
87
|
+
get _fingerPrint () { return '03 0102 1102 1001' }
|
|
88
|
+
|
|
89
|
+
_entryStream (entry) {
|
|
90
|
+
return util.format(
|
|
91
|
+
// '|11 %s %s 1f %s %s %s 00 00',
|
|
92
|
+
'|0f %s %s 07 %s %s %s',
|
|
93
|
+
numToHex(swap32(this._h.currentEntry), 8),
|
|
94
|
+
numToHex(swap32(entry.time - this._h.initialTime), 8),
|
|
95
|
+
numToHex(swap16(entry.currentTemp * 100), 4),
|
|
96
|
+
numToHex(swap16(entry.setTemp * 100), 4),
|
|
97
|
+
numToHex(entry.valvePosition, 2)
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = Thermo
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// homebridge-lib/lib/ServiceDelegate/History/Weather.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
|
+
const util = require('util')
|
|
14
|
+
|
|
15
|
+
const { ServiceDelegate } = homebridgeLib
|
|
16
|
+
const { History } = ServiceDelegate
|
|
17
|
+
const { swap16, swap32, numToHex } = History
|
|
18
|
+
|
|
19
|
+
/** Class for an Eve Weather _History_ service delegate.
|
|
20
|
+
*
|
|
21
|
+
* This delegate sets up a `Services.eve.History` HomeKit service
|
|
22
|
+
* with keys for the following HomeKit characteristics:
|
|
23
|
+
*
|
|
24
|
+
* key | Characteristic
|
|
25
|
+
* ---------------- | ----------------------------------
|
|
26
|
+
* `name` | `Characteristics.hap.Name`
|
|
27
|
+
* `historyRequest` | `Characteristics.eve.HistoryRequest`
|
|
28
|
+
* `setTime` | `Characteristics.eve.SetTime`
|
|
29
|
+
* `historyStatus` | `Characteristics.eve.HistoryStatus`
|
|
30
|
+
* `historyEntries` | `Characteristics.eve.HistoryEntries`
|
|
31
|
+
*
|
|
32
|
+
* This delegate creates the history from the associated
|
|
33
|
+
* `Characteristics.hap.CurrentTemperature`,
|
|
34
|
+
* `Characteristics.hap.CurrentRelativeHumidity`, and
|
|
35
|
+
* `Characteristics.eve.AirPressure` characteristics.
|
|
36
|
+
* @extends ServiceDelegate.History
|
|
37
|
+
* @memberof ServiceDelegate.History
|
|
38
|
+
*/
|
|
39
|
+
class Weather extends ServiceDelegate.History {
|
|
40
|
+
/** Create a new instance of an Eve Weather _History_ service delegate.
|
|
41
|
+
* @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
|
|
42
|
+
* corresponding HomeKit accessory.
|
|
43
|
+
* @param {!object} params - The parameters for the
|
|
44
|
+
* _History_ HomeKit service.
|
|
45
|
+
* @param {!CharacteristicDelegate} temperatureDelegate - A reference to the
|
|
46
|
+
* delegate of the associated `Characteristics.hap.CurrentTemperature`
|
|
47
|
+
* characteristic.
|
|
48
|
+
* @param {?CharacteristicDelegate} humidityDelegate - A reference to the
|
|
49
|
+
* delegate of the associated `Characteristics.hap.CurrentRelativeHumidity`
|
|
50
|
+
* characteristic.
|
|
51
|
+
* @param {?CharacteristicDelegate} pressureDelegate - A reference to the
|
|
52
|
+
* delegate of the associated `Characteristics.eve.AirPressure`
|
|
53
|
+
* characteristic.
|
|
54
|
+
*/
|
|
55
|
+
constructor (
|
|
56
|
+
accessoryDelegate, params,
|
|
57
|
+
temperatureDelegate, humidityDelegate, pressureDelegate
|
|
58
|
+
) {
|
|
59
|
+
super(accessoryDelegate, params)
|
|
60
|
+
if (!(temperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
|
|
61
|
+
throw new TypeError('temperatureDelegate: not a CharacteristicDelegate')
|
|
62
|
+
}
|
|
63
|
+
if (
|
|
64
|
+
humidityDelegate != null &&
|
|
65
|
+
!(humidityDelegate instanceof homebridgeLib.CharacteristicDelegate)
|
|
66
|
+
) {
|
|
67
|
+
throw new TypeError('humidityDelegate: not a CharacteristicDelegate')
|
|
68
|
+
}
|
|
69
|
+
if (
|
|
70
|
+
pressureDelegate != null &&
|
|
71
|
+
!(pressureDelegate instanceof homebridgeLib.CharacteristicDelegate)
|
|
72
|
+
) {
|
|
73
|
+
throw new TypeError('pressureDelegate: not a CharacteristicDelegate')
|
|
74
|
+
}
|
|
75
|
+
this._entry = {
|
|
76
|
+
time: 0,
|
|
77
|
+
temp: temperatureDelegate.value,
|
|
78
|
+
humidity: 0,
|
|
79
|
+
pressure: 0
|
|
80
|
+
}
|
|
81
|
+
temperatureDelegate.on('didSet', (value) => {
|
|
82
|
+
this._entry.temp = value
|
|
83
|
+
})
|
|
84
|
+
if (humidityDelegate != null) {
|
|
85
|
+
this._entry.humidity = humidityDelegate.value
|
|
86
|
+
humidityDelegate.on('didSet', (value) => {
|
|
87
|
+
this._entry.humidity = value
|
|
88
|
+
})
|
|
89
|
+
if (pressureDelegate != null) {
|
|
90
|
+
this._entry.pressure = pressureDelegate.value
|
|
91
|
+
pressureDelegate.on('didSet', (value) => {
|
|
92
|
+
this._entry.pressure = value
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get _fingerPrint () {
|
|
99
|
+
return '03 0102 0202 0302'
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
_entryStream (entry) {
|
|
103
|
+
return util.format(
|
|
104
|
+
'|10 %s %s 07 %s %s %s',
|
|
105
|
+
numToHex(swap32(this._h.currentEntry), 8),
|
|
106
|
+
numToHex(swap32(entry.time - this._h.initialTime), 8),
|
|
107
|
+
numToHex(swap16(entry.temp * 100), 4),
|
|
108
|
+
numToHex(swap16(entry.humidity * 100), 4),
|
|
109
|
+
numToHex(swap16(entry.pressure * 10), 4)
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = Weather
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// homebridge-lib/lib/ServiceDelegate/History/index.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 { ServiceDelegate } = homebridgeLib
|
|
15
|
+
|
|
16
|
+
const util = require('util')
|
|
17
|
+
|
|
18
|
+
/** Eve history keeps time as # seconds since epoch of 2001/01/01.
|
|
19
|
+
* @type {integer}
|
|
20
|
+
*/
|
|
21
|
+
const epoch = Math.round(new Date('2001-01-01T00:00:00Z').valueOf() / 1000)
|
|
22
|
+
|
|
23
|
+
/** Convert Eve date (in # seconds since epoch) to string.
|
|
24
|
+
* @param {integer} d - Eve date as # seconds since epoch.
|
|
25
|
+
* @returns {string} Human readable date string.
|
|
26
|
+
*/
|
|
27
|
+
function dateToString (d) {
|
|
28
|
+
return new Date(1000 * (epoch + d)).toString().slice(0, 24)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function hexToBase64 (value) {
|
|
32
|
+
if (value == null || typeof value !== 'string') {
|
|
33
|
+
throw new TypeError('value: not a string')
|
|
34
|
+
}
|
|
35
|
+
return Buffer.from((value).replace(/[^0-9A-F]/ig, ''), 'hex')
|
|
36
|
+
.toString('base64')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function base64ToHex (value) {
|
|
40
|
+
if (value == null || typeof value !== 'string') {
|
|
41
|
+
throw new TypeError('value: not a string')
|
|
42
|
+
}
|
|
43
|
+
return Buffer.from(value, 'base64').toString('hex')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function swap16 (value) {
|
|
47
|
+
return ((value & 0xFF) << 8) | ((value >>> 8) & 0xFF)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function swap32 (value) {
|
|
51
|
+
return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) |
|
|
52
|
+
((value >>> 8) & 0xFF00) | ((value >>> 24) & 0xFF)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function numToHex (value, length) {
|
|
56
|
+
let s = Number(value >>> 0).toString(16)
|
|
57
|
+
if (s.length % 2 !== 0) {
|
|
58
|
+
s = '0' + s
|
|
59
|
+
}
|
|
60
|
+
if (length) {
|
|
61
|
+
return ('0000000000000' + s).slice(-length)
|
|
62
|
+
}
|
|
63
|
+
return s
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Abstract superclass for an Eve _History_ service delegate.
|
|
67
|
+
*
|
|
68
|
+
* This delegate sets up a `Services.eve.History` HomeKit service
|
|
69
|
+
* with keys for the following HomeKit characteristics:
|
|
70
|
+
*
|
|
71
|
+
* key | Characteristic
|
|
72
|
+
* ---------------- | ----------------------------------
|
|
73
|
+
* `name` | `Characteristics.hap.Name`
|
|
74
|
+
* `historyRequest` | `Characteristics.eve.HistoryRequest`
|
|
75
|
+
* `setTime` | `Characteristics.eve.SetTime`
|
|
76
|
+
* `historyStatus` | `Characteristics.eve.HistoryStatus`
|
|
77
|
+
* `historyEntries` | `Characteristics.eve.HistoryEntries`
|
|
78
|
+
* @abstract
|
|
79
|
+
* @extends ServiceDelegate
|
|
80
|
+
* @memberof ServiceDelegate
|
|
81
|
+
*/
|
|
82
|
+
class History extends ServiceDelegate {
|
|
83
|
+
static get Consumption () { return require('./Consumption') }
|
|
84
|
+
static get Contact () { return require('./Contact') }
|
|
85
|
+
static get Motion () { return require('./Motion') }
|
|
86
|
+
static get On () { return require('./On') }
|
|
87
|
+
static get Power () { return require('./Power') }
|
|
88
|
+
static get Room () { return require('./Room') }
|
|
89
|
+
static get Thermo () { return require('./Thermo') }
|
|
90
|
+
static get Weather () { return require('./Weather') }
|
|
91
|
+
|
|
92
|
+
static get hexToBase64 () { return hexToBase64 }
|
|
93
|
+
static get base64ToHex () { return base64ToHex }
|
|
94
|
+
static get swap16 () { return swap16 }
|
|
95
|
+
static get swap32 () { return swap32 }
|
|
96
|
+
static get numToHex () { return numToHex }
|
|
97
|
+
|
|
98
|
+
/** Create a new instance of an Eve _History_ service delegate.
|
|
99
|
+
* @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
|
|
100
|
+
* corresponding HomeKit accessory.
|
|
101
|
+
* @param {!object} params - The parameters for the
|
|
102
|
+
* _History_ HomeKit service.
|
|
103
|
+
*/
|
|
104
|
+
constructor (accessoryDelegate, params = {}) {
|
|
105
|
+
params.name = accessoryDelegate.name + ' History'
|
|
106
|
+
params.Service = accessoryDelegate.Services.eve.History
|
|
107
|
+
params.hidden = true
|
|
108
|
+
super(accessoryDelegate, params)
|
|
109
|
+
this._memorySize = 6 * 24 * 7 * 4 // Four weeks.
|
|
110
|
+
this._transfer = false
|
|
111
|
+
this._restarted = true
|
|
112
|
+
|
|
113
|
+
this.addCharacteristicDelegate({
|
|
114
|
+
key: 'history',
|
|
115
|
+
silent: true
|
|
116
|
+
})
|
|
117
|
+
if (this.context._history != null) {
|
|
118
|
+
this.values.history = this.context._history
|
|
119
|
+
delete this.context._history
|
|
120
|
+
}
|
|
121
|
+
this._h = this.values.history
|
|
122
|
+
if (this._h == null) {
|
|
123
|
+
this.values.history = {
|
|
124
|
+
firstEntry: 0,
|
|
125
|
+
lastEntry: 0,
|
|
126
|
+
history: ['noValue'],
|
|
127
|
+
usedMemory: 0,
|
|
128
|
+
currentEntry: 1,
|
|
129
|
+
initialTime: 0
|
|
130
|
+
}
|
|
131
|
+
this._h = this.values.history
|
|
132
|
+
} else {
|
|
133
|
+
this.debug('restored %d history entries', this._h.usedMemory)
|
|
134
|
+
}
|
|
135
|
+
if (this._h.refTime != null) {
|
|
136
|
+
this._h.initialTime = this._h.refTime + epoch
|
|
137
|
+
delete this._h.refTime
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
this.addCharacteristicDelegate({
|
|
141
|
+
key: 'historyRequest',
|
|
142
|
+
Characteristic: this.Characteristics.eve.HistoryRequest,
|
|
143
|
+
value: params.historyRequest,
|
|
144
|
+
setter: this._onSetHistoryRequest.bind(this),
|
|
145
|
+
silent: true
|
|
146
|
+
})
|
|
147
|
+
this.addCharacteristicDelegate({
|
|
148
|
+
key: 'setTime',
|
|
149
|
+
Characteristic: this.Characteristics.eve.SetTime,
|
|
150
|
+
value: params.setTime,
|
|
151
|
+
silent: true
|
|
152
|
+
}).on('didSet', (value) => {
|
|
153
|
+
const buffer = Buffer.from(value, 'base64')
|
|
154
|
+
this.debug('SetTime changed to %j', buffer.toString('hex'))
|
|
155
|
+
const date = dateToString(buffer.readUInt32LE())
|
|
156
|
+
this.debug('SetTime changed to %s', date)
|
|
157
|
+
})
|
|
158
|
+
this.addCharacteristicDelegate({
|
|
159
|
+
key: 'historyStatus',
|
|
160
|
+
Characteristic: this.Characteristics.eve.HistoryStatus,
|
|
161
|
+
value: params.historyStatus,
|
|
162
|
+
silent: true
|
|
163
|
+
})
|
|
164
|
+
this.addCharacteristicDelegate({
|
|
165
|
+
key: 'historyEntries',
|
|
166
|
+
Characteristic: this.Characteristics.eve.HistoryEntries,
|
|
167
|
+
value: params.historyEntries,
|
|
168
|
+
getter: this._onGetEntries.bind(this),
|
|
169
|
+
silent: true
|
|
170
|
+
})
|
|
171
|
+
this._accessoryDelegate.heartbeatEnabled = true
|
|
172
|
+
this._accessoryDelegate
|
|
173
|
+
.once('heartbeat', (beat) => {
|
|
174
|
+
this._historyBeat = (beat % 600) + 5
|
|
175
|
+
})
|
|
176
|
+
.on('heartbeat', this._heartbeat.bind(this))
|
|
177
|
+
.on('shutdown', () => {
|
|
178
|
+
this.debug('saved %d history entries', this._h.usedMemory)
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
_addEntry (now = Math.round(new Date().valueOf() / 1000)) {
|
|
183
|
+
this._entry.time = now
|
|
184
|
+
if (this._h.usedMemory < this._memorySize) {
|
|
185
|
+
this._h.usedMemory++
|
|
186
|
+
this._h.firstEntry = 0
|
|
187
|
+
this._h.lastEntry = this._h.usedMemory
|
|
188
|
+
} else {
|
|
189
|
+
this._h.firstEntry++
|
|
190
|
+
this._h.lastEntry = this._h.firstEntry + this._h.usedMemory
|
|
191
|
+
if (this._restarted === true) {
|
|
192
|
+
this._h.history[this._h.lastEntry % this._memorySize] = {
|
|
193
|
+
time: this._entry.time,
|
|
194
|
+
setRefTime: 1
|
|
195
|
+
}
|
|
196
|
+
this._h.firstEntry++
|
|
197
|
+
this._h.lastEntry = this._h.firstEntry + this._h.usedMemory
|
|
198
|
+
this._restarted = false
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (this._h.initialTime === 0) {
|
|
203
|
+
this._h.history[this._h.lastEntry] = {
|
|
204
|
+
time: this._entry.time,
|
|
205
|
+
setRefTime: 1
|
|
206
|
+
}
|
|
207
|
+
this._h.initialTime = this._entry.time
|
|
208
|
+
this._h.lastEntry++
|
|
209
|
+
this._h.usedMemory++
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this._h.history[this._h.lastEntry % this._memorySize] =
|
|
213
|
+
Object.assign({}, this._entry)
|
|
214
|
+
|
|
215
|
+
const usedMemeoryOffset = this._h.usedMemory < this._memorySize ? 1 : 0
|
|
216
|
+
const firstEntryOffset = this._h.usedMemory < this._memorySize ? 0 : 1
|
|
217
|
+
const buffer = Buffer.alloc(1024)
|
|
218
|
+
let offset = 0
|
|
219
|
+
buffer.writeUInt32LE(this._entry.time - this._h.initialTime, offset)
|
|
220
|
+
offset += 4
|
|
221
|
+
buffer.writeUInt32LE(0, offset)
|
|
222
|
+
offset += 4
|
|
223
|
+
buffer.writeUInt32LE(this._h.initialTime - epoch, offset)
|
|
224
|
+
offset += 4
|
|
225
|
+
buffer.write(this._fingerPrint.replace(/[^0-9A-F]/ig, ''), offset, 'hex')
|
|
226
|
+
const length = 1 + 2 * parseInt(this._fingerPrint.slice(0, 2))
|
|
227
|
+
this.debug('fingerprint length: %d', length)
|
|
228
|
+
offset += length
|
|
229
|
+
buffer.writeUInt16LE(this._h.usedMemory + usedMemeoryOffset, offset)
|
|
230
|
+
offset += 2
|
|
231
|
+
buffer.writeUInt16LE(this._memorySize, offset)
|
|
232
|
+
offset += 2
|
|
233
|
+
buffer.writeUInt32LE(this._h.firstEntry + firstEntryOffset, offset)
|
|
234
|
+
offset += 4
|
|
235
|
+
buffer.writeUInt32LE(0, offset)
|
|
236
|
+
offset += 4
|
|
237
|
+
buffer.writeUint8(1, offset)
|
|
238
|
+
offset += 1
|
|
239
|
+
buffer.writeUint8(1, offset)
|
|
240
|
+
offset += 1
|
|
241
|
+
|
|
242
|
+
const value = util.format(
|
|
243
|
+
'%s 00000000 %s [%s] %s %s %s 000000000101',
|
|
244
|
+
numToHex(swap32(this._entry.time - this._h.initialTime), 8),
|
|
245
|
+
numToHex(swap32(this._h.initialTime - epoch), 8),
|
|
246
|
+
this._fingerPrint,
|
|
247
|
+
numToHex(swap16(this._h.usedMemory + usedMemeoryOffset), 4),
|
|
248
|
+
numToHex(swap16(this._memorySize), 4),
|
|
249
|
+
numToHex(swap32(this._h.firstEntry + firstEntryOffset), 8)
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
this.debug('add entry %d: %j', this._h.lastEntry, this._entry)
|
|
253
|
+
this.debug('set history status to: %j', value)
|
|
254
|
+
this.debug('set history status to: %j', buffer.slice(0, offset).toString('hex'))
|
|
255
|
+
this.values.historyStatus = hexToBase64(value)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
_heartbeat (beat) {
|
|
259
|
+
if (beat % 600 === this._historyBeat) {
|
|
260
|
+
this._addEntry()
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async _onSetHistoryRequest (value) {
|
|
265
|
+
const buffer = Buffer.from(value, 'base64')
|
|
266
|
+
this.debug('History Request changed to %j', base64ToHex(value))
|
|
267
|
+
const entry = buffer.readUInt32LE(2)
|
|
268
|
+
this.debug('request entry: %d', entry)
|
|
269
|
+
if (entry !== 0) {
|
|
270
|
+
this._h.currentEntry = entry
|
|
271
|
+
} else {
|
|
272
|
+
this._h.currentEntry = 1
|
|
273
|
+
}
|
|
274
|
+
this._transfer = true
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async _onGetEntries () {
|
|
278
|
+
if (this._h.currentEntry > this._h.lastEntry || !this._transfer) {
|
|
279
|
+
this.debug('send data: 00')
|
|
280
|
+
this._transfer = false
|
|
281
|
+
return hexToBase64('00')
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let dataStream = ''
|
|
285
|
+
for (let i = 0; i < 11; i++) {
|
|
286
|
+
const address = this._h.currentEntry % this._memorySize
|
|
287
|
+
if (
|
|
288
|
+
this._h.history[address].setRefTime === 1 ||
|
|
289
|
+
this._h.currentEntry === this._h.firstEntry + 1
|
|
290
|
+
) {
|
|
291
|
+
this.debug(
|
|
292
|
+
'entry: %s, address %s, reftime: %s (%s)', this._h.currentEntry,
|
|
293
|
+
address, this._h.initialTime - epoch,
|
|
294
|
+
new Date(1000 * this._h.initialTime).toString().slice(0, 24)
|
|
295
|
+
)
|
|
296
|
+
dataStream += util.format(
|
|
297
|
+
'|15 %s 0100000081 %s 00000000000000',
|
|
298
|
+
numToHex(swap32(this._h.currentEntry), 8),
|
|
299
|
+
numToHex(swap32(this._h.initialTime - epoch), 8))
|
|
300
|
+
} else {
|
|
301
|
+
this.debug(
|
|
302
|
+
'entry: %s, address: %s, time: %s (%s)', this._h.currentEntry,
|
|
303
|
+
address, this._h.history[address].time - this._h.initialTime,
|
|
304
|
+
new Date(1000 * this._h.history[address].time).toString().slice(0, 24)
|
|
305
|
+
)
|
|
306
|
+
dataStream += this._entryStream(this._h.history[address])
|
|
307
|
+
}
|
|
308
|
+
this._h.currentEntry++
|
|
309
|
+
if (this._h.currentEntry > this._h.lastEntry) {
|
|
310
|
+
break
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
this.debug('send data: %s', dataStream)
|
|
314
|
+
return hexToBase64(dataStream)
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
module.exports = History
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// homebridge-lib/lib/ServiceDelegate/ServiceLabel.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
|
+
const { ServiceDelegate } = homebridgeLib
|
|
11
|
+
|
|
12
|
+
/** Class for a _ServiceLabel_ service delegate.
|
|
13
|
+
*
|
|
14
|
+
* This delegate sets up a `Services.hap.ServiceLabel` HomeKit service
|
|
15
|
+
* with the following HomeKit characteristics:
|
|
16
|
+
*
|
|
17
|
+
* key | Characteristic | isOptional
|
|
18
|
+
* -------------- | ------------------------------------------- | ----------
|
|
19
|
+
* `name` | `Characteristics.hap.Name` |
|
|
20
|
+
* `namespace` | `Characteristics.hap.ServiceLabelNamespace` |
|
|
21
|
+
* @extends ServiceDelegate
|
|
22
|
+
* @memberof ServiceDelegate
|
|
23
|
+
*/
|
|
24
|
+
class ServiceLabel extends ServiceDelegate {
|
|
25
|
+
/** Create a new instance of an _ServiceLabel_ service delegate.
|
|
26
|
+
* @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
|
|
27
|
+
* corresponding HomeKit accessory.
|
|
28
|
+
* @param {!object} params - The parameters for the
|
|
29
|
+
* _AccessoryInformation_ HomeKit service.
|
|
30
|
+
* @param {!string} params.name - Initial value for
|
|
31
|
+
* `Characteristics.hap.Name`. Also used to prefix log and error messages.
|
|
32
|
+
* @param {!string} params.namespace - Initial value for
|
|
33
|
+
* `Characteristics.hap.ServiceLabelNamespace`.
|
|
34
|
+
*/
|
|
35
|
+
constructor (accessoryDelegate, params = {}) {
|
|
36
|
+
params.name = accessoryDelegate.name
|
|
37
|
+
params.Service = accessoryDelegate.Services.hap.ServiceLabel
|
|
38
|
+
super(accessoryDelegate, params)
|
|
39
|
+
this.addCharacteristicDelegate({
|
|
40
|
+
key: 'namespace',
|
|
41
|
+
Characteristic: this.Characteristics.hap.ServiceLabelNamespace,
|
|
42
|
+
value: params.namespace
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = ServiceLabel
|