homebridge-lib 6.0.2 → 6.1.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.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/cli/hap.js +1 -1
  3. package/cli/json.js +1 -1
  4. package/cli/sysinfo.js +1 -1
  5. package/cli/upnp.js +1 -1
  6. package/index.js +1 -1
  7. package/lib/AccessoryDelegate.js +30 -27
  8. package/lib/AdaptiveLighting.js +1 -1
  9. package/lib/CharacteristicDelegate.js +22 -36
  10. package/lib/Colour.js +1 -1
  11. package/lib/CommandLineParser.js +1 -1
  12. package/lib/CommandLineTool.js +1 -1
  13. package/lib/CustomHomeKitTypes.js +1 -1
  14. package/lib/Delegate.js +31 -33
  15. package/lib/EveHomeKitTypes.js +62 -52
  16. package/lib/HttpClient.js +1 -1
  17. package/lib/JsonFormatter.js +1 -1
  18. package/lib/MyHomeKitTypes.js +88 -97
  19. package/lib/OptionParser.js +27 -2
  20. package/lib/Platform.js +3 -17
  21. package/lib/PropertyDelegate.js +8 -11
  22. package/lib/ServiceDelegate/AccessoryInformation.js +1 -1
  23. package/lib/ServiceDelegate/Battery.js +1 -1
  24. package/lib/ServiceDelegate/Dummy.js +1 -1
  25. package/lib/ServiceDelegate/History/Consumption.js +31 -49
  26. package/lib/ServiceDelegate/History/Contact.js +14 -22
  27. package/lib/ServiceDelegate/History/Light.js +15 -23
  28. package/lib/ServiceDelegate/History/LightLevel.js +113 -0
  29. package/lib/ServiceDelegate/History/Motion.js +67 -80
  30. package/lib/ServiceDelegate/History/On.js +27 -33
  31. package/lib/ServiceDelegate/History/Power.js +46 -52
  32. package/lib/ServiceDelegate/History/Room.js +28 -50
  33. package/lib/ServiceDelegate/History/Thermo.js +19 -33
  34. package/lib/ServiceDelegate/History/Weather.js +33 -56
  35. package/lib/ServiceDelegate/History/index.js +155 -182
  36. package/lib/ServiceDelegate/ServiceLabel.js +1 -1
  37. package/lib/ServiceDelegate/index.js +13 -10
  38. package/lib/SystemInfo.js +3 -2
  39. package/lib/UiServer.js +1 -1
  40. package/lib/UpnpClient.js +1 -1
  41. package/package.json +2 -2
@@ -1,20 +1,13 @@
1
1
  // homebridge-lib/lib/ServiceDelegate/History/Weather.js
2
2
  //
3
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.
4
+ // Copyright © 2017-2023 Erik Baauw. All rights reserved.
9
5
 
10
6
  'use strict'
11
7
 
12
8
  const homebridgeLib = require('../../../index')
13
- const util = require('util')
14
9
 
15
- const { ServiceDelegate } = homebridgeLib
16
- const { History } = ServiceDelegate
17
- const { swap16, swap32, numToHex } = History
10
+ const { History } = homebridgeLib.ServiceDelegate
18
11
 
19
12
  /** Class for an Eve Weather _History_ service delegate.
20
13
  *
@@ -36,7 +29,7 @@ const { swap16, swap32, numToHex } = History
36
29
  * @extends ServiceDelegate.History
37
30
  * @memberof ServiceDelegate.History
38
31
  */
39
- class Weather extends ServiceDelegate.History {
32
+ class Weather extends History {
40
33
  /** Create a new instance of an Eve Weather _History_ service delegate.
41
34
  * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
42
35
  * corresponding HomeKit accessory.
@@ -57,67 +50,51 @@ class Weather extends ServiceDelegate.History {
57
50
  if (!(params.temperatureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
58
51
  throw new TypeError('params.temperatureDelegate: not a CharacteristicDelegate')
59
52
  }
60
- if (
61
- params.humidityDelegate != null &&
62
- !(params.humidityDelegate instanceof homebridgeLib.CharacteristicDelegate)
63
- ) {
64
- throw new TypeError('params.humidityDelegate: not a CharacteristicDelegate')
65
- }
66
- if (
67
- params.airPressureDelegate != null &&
68
- !(params.airPressureDelegate instanceof homebridgeLib.CharacteristicDelegate)
69
- ) {
70
- throw new TypeError('params.airPressureDelegate: not a CharacteristicDelegate')
71
- }
72
- this._entry = {
73
- time: 0,
74
- temp: params.temperatureDelegate.value
75
- }
53
+ this.entry = { t: params.temperatureDelegate.value }
76
54
  params.temperatureDelegate.on('didSet', (value) => {
77
- this._entry.temp = value
55
+ this.entry.t = value
78
56
  })
79
57
  if (params.humidityDelegate != null) {
80
- this._entry.humidity = params.humidityDelegate.value
58
+ if (!(params.humidityDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
59
+ throw new TypeError('params.humidityDelegate: not a CharacteristicDelegate')
60
+ }
61
+ this.entry.h = params.humidityDelegate.value
81
62
  params.humidityDelegate.on('didSet', (value) => {
82
- this._entry.humidity = value
63
+ this.entry.h = value
83
64
  })
84
65
  if (params.airPressureDelegate != null) {
85
- this._entry.pressure = params.airPressureDelegate.value
66
+ if (!(params.airPressureDelegate instanceof homebridgeLib.CharacteristicDelegate)) {
67
+ throw new TypeError('params.airPressureDelegate: not a CharacteristicDelegate')
68
+ }
69
+ this.entry.p = params.airPressureDelegate.value
86
70
  params.airPressureDelegate.on('didSet', (value) => {
87
- this._entry.pressure = value
71
+ this.entry.p = value
88
72
  })
89
73
  }
90
74
  }
91
75
  }
92
76
 
93
- get _fingerPrint () { return '03 0102 0202 0302' }
77
+ get fingerPrint () { return '03 0102 0202 0302' }
94
78
 
95
- _entryStream (entry) {
96
- if (entry.humidity == null) {
97
- return util.format(
98
- '|0c %s %s 01 %s',
99
- numToHex(swap32(this._h.currentEntry), 8),
100
- numToHex(swap32(entry.time - this._h.initialTime), 8),
101
- numToHex(swap16(entry.temp * 100), 4)
102
- )
79
+ entryToBuffer (entry) {
80
+ const buffer = Buffer.alloc(7)
81
+ let o = 0
82
+ if (entry.h == null) {
83
+ buffer.writeUInt8(0x01, o); o += 1
84
+ buffer.writeUInt16LE(entry.t * 100, o); o += 2
85
+ return buffer.slice(0, o)
103
86
  }
104
- if (entry.pressure == null) {
105
- return util.format(
106
- '|0e %s %s 03 %s %s',
107
- numToHex(swap32(this._h.currentEntry), 8),
108
- numToHex(swap32(entry.time - this._h.initialTime), 8),
109
- numToHex(swap16(entry.temp * 100), 4),
110
- numToHex(swap16(entry.humidity * 100), 4)
111
- )
87
+ if (entry.p == null) {
88
+ buffer.writeUInt8(0x03, o); o += 1
89
+ buffer.writeUInt16LE(entry.t * 100, o); o += 2
90
+ buffer.writeUInt16LE(entry.h * 100, o); o += 2
91
+ return buffer.slice(0, o)
112
92
  }
113
- return util.format(
114
- '|10 %s %s 07 %s %s %s',
115
- numToHex(swap32(this._h.currentEntry), 8),
116
- numToHex(swap32(entry.time - this._h.initialTime), 8),
117
- numToHex(swap16(entry.temp * 100), 4),
118
- numToHex(swap16(entry.humidity * 100), 4),
119
- numToHex(swap16(entry.pressure * 10), 4)
120
- )
93
+ buffer.writeUInt8(0x07, o); o += 1
94
+ buffer.writeUInt16LE(entry.t * 100, o); o += 2
95
+ buffer.writeUInt16LE(entry.h * 100, o); o += 2
96
+ buffer.writeUInt16LE(entry.p * 10, o); o += 2
97
+ return buffer.slice(0, o)
121
98
  }
122
99
  }
123
100
 
@@ -1,9 +1,9 @@
1
1
  // homebridge-lib/lib/ServiceDelegate/History/index.js
2
2
  //
3
3
  // Library for Homebridge plugins.
4
- // Copyright © 2017-2022 Erik Baauw. All rights reserved.
4
+ // Copyright © 2017-2023 Erik Baauw. All rights reserved.
5
5
  //
6
- // The logic for handling Eve history was copied from Simone Tisa's
6
+ // The logic for handling Eve history was inspired by Simone Tisa's
7
7
  // fakagato-history repository, copyright © 2017 simont77.
8
8
  // See https://github.com/simont77/fakegato-history.
9
9
 
@@ -13,54 +13,37 @@ const homebridgeLib = require('../../../index')
13
13
 
14
14
  const { ServiceDelegate } = homebridgeLib
15
15
 
16
- const util = require('util')
17
-
18
16
  /** Eve history keeps time as # seconds since epoch of 2001/01/01.
19
17
  * @type {integer}
20
18
  */
21
19
  const epoch = Math.round(new Date('2001-01-01T00:00:00Z').valueOf() / 1000)
22
20
 
23
- /** Convert Eve date (in # seconds since epoch) to string.
24
- * @param {integer} d - Eve date as # seconds since epoch.
21
+ const defaultMemorySize = 6 * 24 * 7 * 4 // 4 weeks of 1 entry per 10 minutes
22
+
23
+ // const historyEntryTypes = {
24
+ // airPressure: { tag: 0x03, length: 2 },
25
+ // consumption: { tag: 0x07, length: 2 },
26
+ // contact: { tag: 0x06, length: 1, event: true },
27
+ // humidity: { tag: 0x02, length: 2 },
28
+ // lastActivation: { },
29
+ // lightLevel: { tag: 0x30, length: 2 },
30
+ // motion: { tag: 0x1C, length: 1, event: true },
31
+ // on: { tag: 0x0E, length: 1, event: true },
32
+ // power: { tag: 0x07, length: 2 },
33
+ // targetTemperature: { tag: 0x11, length: 2 },
34
+ // currentTemperature: { tag: 0x01, length: 2 },
35
+ // timesOpened: { },
36
+ // totalConsumption: { },
37
+ // valvePosition: { tag: 0x10, length: 1 },
38
+ // vocDensity: { tag: 0x22, length: 2 }
39
+ // }
40
+
41
+ /** Convert date (in # seconds since NodeJS epoch) to string.
42
+ * @param {integer} d - # seconds since NodeJS epoch.
25
43
  * @returns {string} Human readable date string.
26
44
  */
27
45
  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
46
+ return new Date(1000 * d).toString().slice(0, 24)
64
47
  }
65
48
 
66
49
  /** Abstract superclass for an Eve _History_ service delegate.
@@ -83,6 +66,7 @@ class History extends ServiceDelegate {
83
66
  static get Consumption () { return require('./Consumption') }
84
67
  static get Contact () { return require('./Contact') }
85
68
  static get Light () { return require('./Light') }
69
+ static get LightLevel () { return require('./LightLevel') }
86
70
  static get Motion () { return require('./Motion') }
87
71
  static get On () { return require('./On') }
88
72
  static get Power () { return require('./Power') }
@@ -90,19 +74,13 @@ class History extends ServiceDelegate {
90
74
  static get Thermo () { return require('./Thermo') }
91
75
  static get Weather () { return require('./Weather') }
92
76
 
93
- static get hexToBase64 () { return hexToBase64 }
94
- static get base64ToHex () { return base64ToHex }
95
- static get swap16 () { return swap16 }
96
- static get swap32 () { return swap32 }
97
- static get numToHex () { return numToHex }
98
-
99
77
  /** Create a new instance of an Eve _History_ service delegate.
100
78
  * @param {!AccessoryDelegate} accessoryDelegate - The delegate of the
101
79
  * corresponding HomeKit accessory.
102
80
  * @param {!object} params - The parameters for the
103
81
  * _History_ HomeKit service.
104
- * @param {integer} [params.memorySize=2304] - The memory size, in number of
105
- * history entries. The default is 4 weeks of 6 entries per hour.
82
+ * @param {integer} [params.memorySize=4032] - The memory size, in number of
83
+ * history entries. The default is 4 weeks of 1 entry per 10 minutes.
106
84
  * @param {?boolean} params.config - Expose config.
107
85
  */
108
86
  constructor (accessoryDelegate, params = {}) {
@@ -110,35 +88,39 @@ class History extends ServiceDelegate {
110
88
  params.Service = accessoryDelegate.Services.eve.History
111
89
  params.hidden = true
112
90
  super(accessoryDelegate, params)
113
- this._memorySize = params.memorySize == null ? 4032 : params.memorySize
91
+ const memorySize = params.memorySize == null ? defaultMemorySize : params.memorySize
114
92
  this._transfer = false
115
- this._restarted = true
116
93
 
117
94
  this.addCharacteristicDelegate({
118
95
  key: 'history',
119
96
  silent: true
120
97
  })
121
- if (this.context._history != null) {
122
- this.values.history = this.context._history
123
- delete this.context._history
124
- }
125
98
  this._h = this.values.history
126
99
  if (this._h == null) {
127
100
  this.values.history = {
128
- firstEntry: 0,
129
- lastEntry: 0,
130
- history: ['noValue'],
131
- usedMemory: 0,
132
- currentEntry: 1,
133
- initialTime: 0
101
+ memorySize,
102
+ firstEntry: 1,
103
+ lastEntry: 1,
104
+ entryOffset: 0,
105
+ entries: [null, null],
106
+ initialTime: History.now()
107
+ }
108
+ this._h = this.values.history
109
+ } else if (this._h.memorySize !== memorySize) {
110
+ this.values.history = {
111
+ memorySize,
112
+ firstEntry: this._h.lastEntry,
113
+ lastEntry: this._h.lastEntry,
114
+ entryOffset: this._h.lastEntry - 1,
115
+ entries: [null, null],
116
+ initialTime: this._h.initialTime
134
117
  }
135
118
  this._h = this.values.history
136
119
  } else {
137
- this.debug('restored %d history entries', this._h.usedMemory)
138
- }
139
- if (this._h.refTime != null) {
140
- this._h.initialTime = this._h.refTime + epoch
141
- delete this._h.refTime
120
+ this.debug(
121
+ 'restored %d history entries (%d to %d)', this._h.entries.length,
122
+ this._h.firstEntry, this._h.lastEntry
123
+ )
142
124
  }
143
125
 
144
126
  this.addCharacteristicDelegate({
@@ -156,8 +138,8 @@ class History extends ServiceDelegate {
156
138
  silent: true
157
139
  }).on('didSet', (value) => {
158
140
  const buffer = Buffer.from(value, 'base64')
159
- this.debug('SetTime changed to %j', buffer.toString('hex'))
160
- const date = dateToString(buffer.readUInt32LE())
141
+ this.vdebug('SetTime changed to %j', buffer.toString('hex'))
142
+ const date = dateToString(buffer.readUInt32LE() + epoch)
161
143
  this.debug('SetTime changed to %s', date)
162
144
  })
163
145
 
@@ -202,157 +184,148 @@ class History extends ServiceDelegate {
202
184
  .once('heartbeat', (beat) => {
203
185
  this._historyBeat = (beat % 600) + 5
204
186
  })
205
- .on('heartbeat', this._heartbeat.bind(this))
187
+ .on('heartbeat', (beat) => {
188
+ if (beat % 600 === this._historyBeat) {
189
+ this.addEntry(
190
+ Object.assign({ time: History.now() }, this.entry)
191
+ )
192
+ }
193
+ })
206
194
  .on('shutdown', () => {
207
- this.debug('saved %d history entries', this._h.usedMemory)
195
+ this.debug(
196
+ 'saved %d history entries (%d to %d)', this._h.entries.length,
197
+ this._h.firstEntry, this._h.lastEntry
198
+ )
208
199
  })
209
200
  }
210
201
 
211
- _addEntry (now = Math.round(new Date().valueOf() / 1000)) {
212
- this._entry.time = now
213
- if (this._h.usedMemory < this._memorySize) {
214
- this._h.usedMemory++
215
- this._h.firstEntry = 0
216
- this._h.lastEntry = this._h.usedMemory
217
- } else {
218
- this._h.firstEntry++
219
- this._h.lastEntry = this._h.firstEntry + this._h.usedMemory
220
- if (this._restarted === true) {
221
- this._h.history[this._h.lastEntry % this._memorySize] = {
222
- time: this._entry.time,
223
- setRefTime: 1
224
- }
225
- this._h.firstEntry++
226
- this._h.lastEntry = this._h.firstEntry + this._h.usedMemory
227
- this._restarted = false
228
- }
229
- }
230
-
231
- if (this._h.initialTime === 0) {
232
- this._h.history[this._h.lastEntry] = {
233
- time: this._entry.time,
234
- setRefTime: 1
235
- }
236
- this._h.initialTime = this._entry.time
237
- this._h.lastEntry++
238
- this._h.usedMemory++
239
- }
240
-
241
- this._h.history[this._h.lastEntry % this._memorySize] =
242
- Object.assign({}, this._entry)
243
-
244
- const usedMemeoryOffset = this._h.usedMemory < this._memorySize ? 1 : 0
245
- const firstEntryOffset = this._h.usedMemory < this._memorySize ? 0 : 1
202
+ /** Return current time as # seconds since NodeJS epoch.
203
+ * @returns {integer} # seconds since NodeJS epoch.
204
+ */
205
+ static now () { return Math.round(new Date().valueOf() / 1000) }
246
206
 
247
- // const buffer = Buffer.alloc(1024)
248
- // let offset = 0
249
- // buffer.writeUInt32LE(this._entry.time - this._h.initialTime, offset)
250
- // offset += 4
251
- // buffer.writeUInt32LE(0, offset)
252
- // offset += 4
253
- // buffer.writeUInt32LE(this._h.initialTime - epoch, offset)
254
- // offset += 4
255
- // buffer.write(this._fingerPrint.replace(/[^0-9A-F]/ig, ''), offset, 'hex')
256
- // const length = 1 + 2 * parseInt(this._fingerPrint.slice(0, 2))
257
- // this.debug('fingerprint length: %d', length)
258
- // offset += length
259
- // buffer.writeUInt16LE(this._h.usedMemory + usedMemeoryOffset, offset)
260
- // offset += 2
261
- // buffer.writeUInt16LE(this._memorySize, offset)
262
- // offset += 2
263
- // buffer.writeUInt32LE(this._h.firstEntry + firstEntryOffset, offset)
264
- // offset += 4
265
- // buffer.writeUInt32LE(0, offset)
266
- // offset += 4
267
- // buffer.writeUint8(1, offset)
268
- // offset += 1
269
- // buffer.writeUint8(1, offset)
270
- // offset += 1
207
+ /** Convert date intp `Characteristics.eve.LastActivation` characteristic value.
208
+ * @param {integer} date - # seconds since NodeJS epoch.
209
+ * @returns {integer} Value for last activation.
210
+ */
211
+ lastActivationValue (date = History.now()) { return date - this._h.initialTime }
271
212
 
272
- const value = util.format(
273
- '%s 00000000 %s [%s] %s %s %s 00000000 0101',
274
- numToHex(swap32(this._entry.time - this._h.initialTime), 8),
275
- numToHex(swap32(this._h.initialTime - epoch), 8),
276
- this._fingerPrint,
277
- numToHex(swap16(this._h.usedMemory + usedMemeoryOffset), 4),
278
- numToHex(swap16(this._memorySize), 4),
279
- numToHex(swap32(this._h.firstEntry + firstEntryOffset), 8)
280
- )
213
+ /** Return the history fingerprint.
214
+ * @abstract
215
+ * @returns {string} fingerprint - Hex string with the fingerprint.
216
+ */
217
+ get fingerPrint () { return '00' }
281
218
 
282
- this.debug('add entry %d: %j', this._h.lastEntry, this._entry)
283
- this.debug('set history status to: %j', value)
284
- // this.debug('set history status to: %j', buffer.slice(0, offset).toString('hex'))
285
- this.values.historyStatus = hexToBase64(value)
219
+ /** Convert a history entry to a buffer.
220
+ * @abstract
221
+ * @param {object} entry - The entry.
222
+ * @returns {Buffer} A Buffer with the values from the entry.
223
+ */
224
+ entryToBuffer (entry) {
225
+ return Buffer.alloc(0)
286
226
  }
287
227
 
288
- _heartbeat (beat) {
289
- if (beat % 600 === this._historyBeat) {
290
- this._addEntry()
228
+ /** Add an entry to the history.
229
+ * @param {object} entry - The entry.
230
+ */
231
+ addEntry (entry) {
232
+ if (this._h.memorySize > 0) {
233
+ if (this._h.lastEntry >= this._h.memorySize) {
234
+ this._h.firstEntry++
235
+ }
236
+ this._h.lastEntry++
237
+ const index = (this._h.lastEntry - this._h.entryOffset) % this._h.memorySize
238
+ this.debug(
239
+ 'History Entries: set entry %d (index %d) to %j',
240
+ this._h.lastEntry, index, entry
241
+ )
242
+ this._h.entries[index] = entry
291
243
  }
244
+
245
+ this.debug('set History Status to %d .. %d', this._h.firstEntry, this._h.lastEntry)
246
+ const buffer = Buffer.alloc(1024)
247
+ let offset = 0
248
+ buffer.writeUInt32LE(entry.time - this._h.initialTime, offset); offset += 4
249
+ buffer.writeUInt32LE(0, offset); offset += 4
250
+ buffer.writeUInt32LE(this._h.initialTime - epoch, offset); offset += 4
251
+ buffer.write(this.fingerPrint.replace(/[^0-9A-F]/ig, ''), offset, 'hex')
252
+ offset += 1 + 2 * parseInt(this.fingerPrint.slice(0, 2))
253
+ buffer.writeUInt16LE(this._h.lastEntry - this._h.firstEntry + 1, offset); offset += 2
254
+ buffer.writeUInt16LE(this._h.memorySize, offset); offset += 2
255
+ buffer.writeUInt32LE(this._h.firstEntry, offset); offset += 4
256
+ buffer.writeUInt32LE(0, offset); offset += 4
257
+ buffer.writeUInt8(1, offset); offset += 1
258
+ buffer.writeUInt8(1, offset); offset += 1
259
+ const value = buffer.slice(0, offset)
260
+ this.values.historyStatus = value.toString('base64')
292
261
  }
293
262
 
294
263
  async _onSetHistoryRequest (value) {
295
264
  const buffer = Buffer.from(value, 'base64')
296
- this.debug('History Request changed to %j', base64ToHex(value))
265
+ this.vdebug('History Request changed to %j', buffer.toString('hex'))
297
266
  const entry = buffer.readUInt32LE(2)
298
- this.debug('request entry: %d', entry)
299
- if (entry !== 0) {
300
- this._h.currentEntry = entry
301
- } else {
302
- this._h.currentEntry = 1
303
- }
267
+ this.debug(
268
+ 'History Request changed to %d (%d to %d)', entry,
269
+ this._h.firstEntry, this._h.lastEntry
270
+ )
271
+ this._currentEntry = Math.max(this._h.firstEntry, entry)
304
272
  this._transfer = true
305
273
  }
306
274
 
307
275
  async _onGetEntries () {
308
- if (this._h.currentEntry > this._h.lastEntry || !this._transfer) {
309
- this.debug('send data: 00')
276
+ if (this._currentEntry > this._h.lastEntry || !this._transfer) {
277
+ this.debug('History Entries: no entry')
278
+ this.vdebug('History Entries: send data: 00')
310
279
  this._transfer = false
311
- return hexToBase64('00')
280
+ return Buffer.from('00', 'hex').toString('base64')
312
281
  }
313
282
 
314
- let dataStream = ''
283
+ const buffer = Buffer.alloc(1024)
284
+ let offset = 0
315
285
  for (let i = 0; i < 11; i++) {
316
- const address = this._memorySize === 0
317
- ? 0
318
- : this._h.currentEntry % this._memorySize
319
- if (
320
- this._h.history[address].setRefTime === 1 ||
321
- this._h.currentEntry === this._h.firstEntry + 1
322
- ) {
286
+ const index = this._h.memorySize === 0
287
+ ? 1
288
+ : (this._currentEntry - this._h.entryOffset) % this._h.memorySize
289
+ if (this._currentEntry === this._h.firstEntry) {
323
290
  this.debug(
324
- 'entry: %s, address %s, reftime: %s (%s)', this._h.currentEntry,
325
- address, this._h.initialTime - epoch,
326
- new Date(1000 * this._h.initialTime).toString().slice(0, 24)
291
+ 'History Entries (%d/11): entry %d (index: %d): %j (%s)',
292
+ i, this._currentEntry, index, { initialTime: this._h.initialTime - epoch },
293
+ dateToString(this._h.initialTime)
327
294
  )
328
- dataStream += util.format(
329
- '|15 %s 0100000081 %s 00000000000000',
330
- numToHex(swap32(this._h.currentEntry), 8),
331
- numToHex(swap32(this._h.initialTime - epoch), 8))
295
+ buffer.writeUInt8(21, offset); offset += 1
296
+ buffer.writeUInt32LE(this._currentEntry, offset); offset += 4
297
+ buffer.write('0100000081', offset, 'hex'); offset += 5
298
+ buffer.writeUInt32LE(this._h.initialTime - epoch, offset); offset += 4
299
+ buffer.write('00000000000000', offset, 'hex'); offset += 7
332
300
  } else {
301
+ const entry = this._h.entries[index]
333
302
  this.debug(
334
- 'entry: %s, address: %s, time: %s (%s)', this._h.currentEntry,
335
- address, this._h.history[address].time - this._h.initialTime,
336
- new Date(1000 * this._h.history[address].time).toString().slice(0, 24)
303
+ 'History Entries (%d/11): entry %d (index: %d): %j (%s)',
304
+ i, this._currentEntry, index, entry, dateToString(entry.time)
337
305
  )
338
- dataStream += this._entryStream(this._h.history[address])
306
+ const b = this.entryToBuffer(entry)
307
+ buffer.writeUInt8(b.length + 9, offset); offset += 1
308
+ buffer.writeUInt32LE(this._currentEntry, offset); offset += 4
309
+ buffer.writeUInt32LE(entry.time - this._h.initialTime, offset); offset += 4
310
+ b.copy(buffer, offset); offset += b.length
339
311
  }
340
- this._h.currentEntry++
341
- if (this._h.currentEntry > this._h.lastEntry) {
312
+ this._currentEntry++
313
+ if (this._currentEntry > this._h.lastEntry) {
342
314
  break
343
315
  }
344
316
  }
345
- this.debug('send data: %s', dataStream)
346
- return hexToBase64(dataStream)
317
+ const value = buffer.slice(0, offset)
318
+ this.vdebug('History Entries: send data: %s', value.toString('hex'))
319
+ return value.toString('base64')
347
320
  }
348
321
 
349
322
  async _onSetConfig (value) {
350
- // const buffer = Buffer.from(value, 'base64')
351
- this.debug('Config Request changed to %j', base64ToHex(value))
323
+ const buffer = Buffer.from(value, 'base64')
324
+ this.vdebug('Config Request changed to %j', buffer.toString('hex'))
352
325
  }
353
326
 
354
327
  async _onGetConfig () {
355
- return hexToBase64('D200')
328
+ return Buffer.from('D200', 'hex').toString('base64')
356
329
  }
357
330
  }
358
331
 
@@ -1,7 +1,7 @@
1
1
  // homebridge-lib/lib/ServiceDelegate/ServiceLabel.js
2
2
  //
3
3
  // Library for Homebridge plugins.
4
- // Copyright © 2017-2022 Erik Baauw. All rights reserved.
4
+ // Copyright © 2017-2023 Erik Baauw. All rights reserved.
5
5
 
6
6
  'use strict'
7
7
 
@@ -1,7 +1,7 @@
1
1
  // homebridge-lib/lib/ServiceDelegate/index.js
2
2
  //
3
3
  // Library for Homebridge plugins.
4
- // Copyright © 2017-2022 Erik Baauw. All rights reserved.
4
+ // Copyright © 2017-2023 Erik Baauw. All rights reserved.
5
5
 
6
6
  'use strict'
7
7
 
@@ -78,7 +78,7 @@ class ServiceDelegate extends homebridgeLib.Delegate {
78
78
  : this._accessory.getServiceByUUIDAndSubType(params.Service, params.subtype)
79
79
  if (this._service == null) {
80
80
  this._service = this._accessory.addService(
81
- new params.Service(this.name, params.subtype)
81
+ new params.Service(null, params.subtype)
82
82
  )
83
83
  }
84
84
  this._accessoryDelegate._linkServiceDelegate(this)
@@ -116,25 +116,28 @@ class ServiceDelegate extends homebridgeLib.Delegate {
116
116
  this.addCharacteristicDelegate({
117
117
  key: 'name',
118
118
  Characteristic: this.Characteristics.hap.Name,
119
- silent: true,
120
119
  value: params.name
121
120
  })
122
-
123
- if (params.exposeConfiguredName) {
121
+ if (this._service.constructor.name !== 'AccessoryInformation') {
124
122
  this.addCharacteristicDelegate({
125
123
  key: 'configuredName',
126
124
  Characteristic: this.Characteristics.hap.ConfiguredName,
125
+ props: {
126
+ perms: [
127
+ this.Characteristic.Perms.PAIRED_READ,
128
+ this.Characteristic.Perms.NOTIFY,
129
+ this.Characteristic.Perms.PAIRED_WRITE,
130
+ this.Characteristic.Perms.HIDDEN
131
+ ]
132
+ },
127
133
  value: params.name,
128
134
  setter: (value) => {
129
135
  if (value == null || value === '') {
130
- throw new Error('cannot be empty')
136
+ throw new RangeError('cannot be empty')
131
137
  }
132
138
  }
133
139
  }).on('didSet', (value) => {
134
140
  this.name = value
135
- for (const key in this._characteristicDelegates) {
136
- this._characteristicDelegates[key].name = value
137
- }
138
141
  if (params.primaryService) {
139
142
  accessoryDelegate.values.name = value
140
143
  }
@@ -173,7 +176,7 @@ class ServiceDelegate extends homebridgeLib.Delegate {
173
176
  * Removes the associated HomeKit service.
174
177
  */
175
178
  destroy () {
176
- this.debug('destroy %s (%s)', this._key, this._service.displayName)
179
+ this.debug('destroy %s (%s)', this._key, this.constructor.name)
177
180
  this._accessoryDelegate._unlinkServiceDelegate(this)
178
181
  this.removeAllListeners()
179
182
  for (const key in this._characteristicDelegates) {
package/lib/SystemInfo.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // homebridge-lib/lib/SystemInfo.js
2
2
  //
3
3
  // Library for Homebridge plugins.
4
- // Copyright © 2019-2022 Erik Baauw. All rights reserved.
4
+ // Copyright © 2019-2023 Erik Baauw. All rights reserved.
5
5
 
6
6
  'use strict'
7
7
 
@@ -49,7 +49,8 @@ const rpiInfo = {
49
49
  17: '4B',
50
50
  18: 'Zero 2 W',
51
51
  19: '400',
52
- 20: 'CM4'
52
+ 20: 'CM4',
53
+ 21: 'CM4S'
53
54
  },
54
55
  processors: {
55
56
  0: 'BCM2835',