homebridge-nest-accfactory 0.0.4-a
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/CHANGELOG.md +27 -0
- package/LICENSE +176 -0
- package/README.md +121 -0
- package/config.schema.json +107 -0
- package/dist/HomeKitDevice.js +441 -0
- package/dist/HomeKitHistory.js +2835 -0
- package/dist/camera.js +1276 -0
- package/dist/doorbell.js +122 -0
- package/dist/index.js +35 -0
- package/dist/nexustalk.js +741 -0
- package/dist/protect.js +240 -0
- package/dist/protobuf/google/rpc/status.proto +91 -0
- package/dist/protobuf/google/rpc/stream_body.proto +26 -0
- package/dist/protobuf/google/trait/product/camera.proto +53 -0
- package/dist/protobuf/googlehome/foyer.proto +208 -0
- package/dist/protobuf/nest/messages.proto +8 -0
- package/dist/protobuf/nest/services/apigateway.proto +107 -0
- package/dist/protobuf/nest/trait/audio.proto +7 -0
- package/dist/protobuf/nest/trait/cellular.proto +313 -0
- package/dist/protobuf/nest/trait/debug.proto +37 -0
- package/dist/protobuf/nest/trait/detector.proto +41 -0
- package/dist/protobuf/nest/trait/diagnostics.proto +87 -0
- package/dist/protobuf/nest/trait/firmware.proto +221 -0
- package/dist/protobuf/nest/trait/guest.proto +105 -0
- package/dist/protobuf/nest/trait/history.proto +345 -0
- package/dist/protobuf/nest/trait/humanlibrary.proto +19 -0
- package/dist/protobuf/nest/trait/hvac.proto +1353 -0
- package/dist/protobuf/nest/trait/input.proto +29 -0
- package/dist/protobuf/nest/trait/lighting.proto +61 -0
- package/dist/protobuf/nest/trait/located.proto +193 -0
- package/dist/protobuf/nest/trait/media.proto +68 -0
- package/dist/protobuf/nest/trait/network.proto +352 -0
- package/dist/protobuf/nest/trait/occupancy.proto +373 -0
- package/dist/protobuf/nest/trait/olive.proto +15 -0
- package/dist/protobuf/nest/trait/pairing.proto +85 -0
- package/dist/protobuf/nest/trait/product/camera.proto +283 -0
- package/dist/protobuf/nest/trait/product/detect.proto +67 -0
- package/dist/protobuf/nest/trait/product/doorbell.proto +18 -0
- package/dist/protobuf/nest/trait/product/guard.proto +59 -0
- package/dist/protobuf/nest/trait/product/protect.proto +344 -0
- package/dist/protobuf/nest/trait/promonitoring.proto +14 -0
- package/dist/protobuf/nest/trait/resourcedirectory.proto +32 -0
- package/dist/protobuf/nest/trait/safety.proto +119 -0
- package/dist/protobuf/nest/trait/security.proto +516 -0
- package/dist/protobuf/nest/trait/selftest.proto +78 -0
- package/dist/protobuf/nest/trait/sensor.proto +291 -0
- package/dist/protobuf/nest/trait/service.proto +46 -0
- package/dist/protobuf/nest/trait/structure.proto +85 -0
- package/dist/protobuf/nest/trait/system.proto +51 -0
- package/dist/protobuf/nest/trait/test.proto +15 -0
- package/dist/protobuf/nest/trait/ui.proto +65 -0
- package/dist/protobuf/nest/trait/user.proto +98 -0
- package/dist/protobuf/nest/trait/voiceassistant.proto +30 -0
- package/dist/protobuf/nestlabs/eventingapi/v1.proto +83 -0
- package/dist/protobuf/nestlabs/gateway/v1.proto +273 -0
- package/dist/protobuf/nestlabs/gateway/v2.proto +96 -0
- package/dist/protobuf/nestlabs/history/v1.proto +73 -0
- package/dist/protobuf/root.proto +64 -0
- package/dist/protobuf/wdl-event-importance.proto +11 -0
- package/dist/protobuf/wdl.proto +450 -0
- package/dist/protobuf/weave/common.proto +144 -0
- package/dist/protobuf/weave/trait/audio.proto +12 -0
- package/dist/protobuf/weave/trait/auth.proto +22 -0
- package/dist/protobuf/weave/trait/description.proto +32 -0
- package/dist/protobuf/weave/trait/heartbeat.proto +38 -0
- package/dist/protobuf/weave/trait/locale.proto +20 -0
- package/dist/protobuf/weave/trait/network.proto +24 -0
- package/dist/protobuf/weave/trait/pairing.proto +8 -0
- package/dist/protobuf/weave/trait/peerdevices.proto +18 -0
- package/dist/protobuf/weave/trait/power.proto +86 -0
- package/dist/protobuf/weave/trait/schedule.proto +76 -0
- package/dist/protobuf/weave/trait/security.proto +343 -0
- package/dist/protobuf/weave/trait/telemetry/tunnel.proto +37 -0
- package/dist/protobuf/weave/trait/time.proto +16 -0
- package/dist/res/Nest_camera_connecting.h264 +0 -0
- package/dist/res/Nest_camera_connecting.jpg +0 -0
- package/dist/res/Nest_camera_off.h264 +0 -0
- package/dist/res/Nest_camera_off.jpg +0 -0
- package/dist/res/Nest_camera_offline.h264 +0 -0
- package/dist/res/Nest_camera_offline.jpg +0 -0
- package/dist/res/Nest_camera_transfer.jpg +0 -0
- package/dist/streamer.js +344 -0
- package/dist/system.js +3112 -0
- package/dist/tempsensor.js +99 -0
- package/dist/thermostat.js +1026 -0
- package/dist/weather.js +205 -0
- package/dist/webrtc.js +55 -0
- package/package.json +66 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
// HomeKitDevice class
|
|
2
|
+
//
|
|
3
|
+
// This is the base class for all HomeKit accessories we code for in Homebridge/HAP-NodeJS
|
|
4
|
+
//
|
|
5
|
+
// The deviceData structure should at a minimum contain the following elements:
|
|
6
|
+
//
|
|
7
|
+
// Homebridge Plugin:
|
|
8
|
+
//
|
|
9
|
+
// uuid
|
|
10
|
+
// serial_number
|
|
11
|
+
// software_version
|
|
12
|
+
// description
|
|
13
|
+
// manufacturer
|
|
14
|
+
// model
|
|
15
|
+
//
|
|
16
|
+
// HAP-NodeJS Library Accessory:
|
|
17
|
+
//
|
|
18
|
+
// uuid
|
|
19
|
+
// serial_number
|
|
20
|
+
// software_version
|
|
21
|
+
// description
|
|
22
|
+
// manufacturer
|
|
23
|
+
// model
|
|
24
|
+
// hkUsername
|
|
25
|
+
// hkPairingCode
|
|
26
|
+
//
|
|
27
|
+
// Following constants should be overridden in the module loading this class file
|
|
28
|
+
//
|
|
29
|
+
// HomeKitDevice.HOMEKITHISTORY
|
|
30
|
+
// HomeKitDevice.PLUGIN_NAME
|
|
31
|
+
// HomeKitDevice.PLATFORM_NAME
|
|
32
|
+
//
|
|
33
|
+
// The following functions should be overriden in your class which extends this
|
|
34
|
+
//
|
|
35
|
+
// HomeKitDevice.addServices()
|
|
36
|
+
// HomeKitDevice.removeServices()
|
|
37
|
+
// HomeKitDevice.updateServices(deviceData)
|
|
38
|
+
// HomeKitDevice.messageServices(type, message)
|
|
39
|
+
//
|
|
40
|
+
// Code version 6/9/2024
|
|
41
|
+
// Mark Hulskamp
|
|
42
|
+
'use strict';
|
|
43
|
+
|
|
44
|
+
// Define nodejs module requirements
|
|
45
|
+
import EventEmitter from 'node:events';
|
|
46
|
+
|
|
47
|
+
// Define our HomeKit device class
|
|
48
|
+
export default class HomeKitDevice {
|
|
49
|
+
static ADD = 'HomeKitDevice.add'; // Device add message
|
|
50
|
+
static UPDATE = 'HomeKitDevice.update'; // Device update message
|
|
51
|
+
static REMOVE = 'HomeKitDevice.remove'; // Device remove message
|
|
52
|
+
static SET = 'HomeKitDevice.set'; // Device set property message
|
|
53
|
+
static GET = 'HomeKitDevice.get'; // Device get property message
|
|
54
|
+
static PLUGIN_NAME = undefined; // Homebridge plugin name (override)
|
|
55
|
+
static PLATFORM_NAME = undefined; // Homebridge platform name (override)
|
|
56
|
+
static HISTORY = undefined; // HomeKit History object (override)
|
|
57
|
+
|
|
58
|
+
deviceData = {}; // The devices data we store
|
|
59
|
+
historyService = undefined; // HomeKit history service
|
|
60
|
+
accessory = undefined; // Accessory service for this device
|
|
61
|
+
hap = undefined; // HomeKit Accessory Protocol API stub
|
|
62
|
+
log = undefined; // Logging function object
|
|
63
|
+
|
|
64
|
+
// Internal data only for this class
|
|
65
|
+
#platform = undefined; // Homebridge platform api
|
|
66
|
+
#eventEmitter = undefined; // Event emitter to use for comms
|
|
67
|
+
|
|
68
|
+
constructor(accessory, api, log, eventEmitter, deviceData) {
|
|
69
|
+
// Validate the passed in logging object. We are expecting certain functions to be present
|
|
70
|
+
if (
|
|
71
|
+
typeof log?.info === 'function' &&
|
|
72
|
+
typeof log?.success === 'function' &&
|
|
73
|
+
typeof log?.warn === 'function' &&
|
|
74
|
+
typeof log?.error === 'function' &&
|
|
75
|
+
typeof log?.debug === 'function'
|
|
76
|
+
) {
|
|
77
|
+
this.log = log;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Workout if we're running under HomeBridge or HAP-NodeJS library
|
|
81
|
+
if (typeof api?.version === 'number' && typeof api?.hap === 'object' && typeof api?.HAPLibraryVersion === 'undefined') {
|
|
82
|
+
// We have the HomeBridge version number and hap API object
|
|
83
|
+
this.hap = api.hap;
|
|
84
|
+
this.#platform = api;
|
|
85
|
+
|
|
86
|
+
this?.log?.debug && this.log.debug('HomeKitDevice module using Homebridge backend for "%s"', deviceData?.description);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (typeof api?.HAPLibraryVersion === 'function' && typeof api?.version === 'undefined' && typeof api?.hap === 'undefined') {
|
|
90
|
+
// As we're missing the HomeBridge entry points but have the HAP library version
|
|
91
|
+
this.hap = api;
|
|
92
|
+
|
|
93
|
+
this?.log?.debug && this.log.debug('HomeKitDevice module using HAP-NodeJS library for "%s"', deviceData?.description);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Validate if eventEmitter object passed to us is an instance of EventEmitter
|
|
97
|
+
if (eventEmitter instanceof EventEmitter === true) {
|
|
98
|
+
this.#eventEmitter = eventEmitter;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// If we have a valid EventEmitter and a device uuid
|
|
102
|
+
// Setup a listener for messages to this device
|
|
103
|
+
if (this.#eventEmitter !== undefined && typeof this.deviceData?.uuid === 'string' && this.deviceData.uuid !== '') {
|
|
104
|
+
this.#eventEmitter.addListener(this.deviceData.uuid, this.#message.bind(this));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Make copy of current data and store in this object
|
|
108
|
+
// eslint-disable-next-line no-undef
|
|
109
|
+
this.deviceData = structuredClone(deviceData);
|
|
110
|
+
|
|
111
|
+
// See if we were passed in an existing accessory object or array of accessory objects
|
|
112
|
+
// Mainly used to restore a HomeBridge cached accessory
|
|
113
|
+
if (
|
|
114
|
+
typeof accessory === 'object' &&
|
|
115
|
+
typeof this?.hap?.uuid?.generate === 'function' &&
|
|
116
|
+
typeof deviceData.uuid === 'string' &&
|
|
117
|
+
this.#platform !== undefined
|
|
118
|
+
) {
|
|
119
|
+
let uuid = this.hap.uuid.generate(HomeKitDevice.PLUGIN_NAME + '_' + deviceData.uuid);
|
|
120
|
+
|
|
121
|
+
if (Array.isArray(accessory) === true) {
|
|
122
|
+
this.accessory = accessory.find((accessory) => accessory.UUID === uuid);
|
|
123
|
+
}
|
|
124
|
+
if (Array.isArray(accessory) === false && typeof accessory?.UUID === 'string' && accessory.UUID === uuid) {
|
|
125
|
+
this.accessory = accessory;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Class functions
|
|
131
|
+
async add(accessoryName, accessoryCategory, useHistoryService) {
|
|
132
|
+
if (
|
|
133
|
+
this.hap === undefined ||
|
|
134
|
+
HomeKitDevice.PLUGIN_NAME === undefined ||
|
|
135
|
+
HomeKitDevice.PLATFORM_NAME === undefined ||
|
|
136
|
+
typeof accessoryName !== 'string' ||
|
|
137
|
+
accessoryName === '' ||
|
|
138
|
+
typeof this.hap.Categories[accessoryCategory] === 'undefined' ||
|
|
139
|
+
typeof useHistoryService !== 'boolean' ||
|
|
140
|
+
typeof this.deviceData !== 'object' ||
|
|
141
|
+
typeof this.deviceData?.uuid !== 'string' ||
|
|
142
|
+
this.deviceData.uuid === '' ||
|
|
143
|
+
typeof this.deviceData?.serial_number !== 'string' ||
|
|
144
|
+
this.deviceData.serial_number === '' ||
|
|
145
|
+
typeof this.deviceData?.software_version !== 'string' ||
|
|
146
|
+
this.deviceData.software_version === '' ||
|
|
147
|
+
(typeof this.deviceData?.description !== 'string' && this.deviceData.description === '') ||
|
|
148
|
+
typeof this.deviceData?.model !== 'string' ||
|
|
149
|
+
this.deviceData.model === '' ||
|
|
150
|
+
typeof this.deviceData?.manufacturer !== 'string' ||
|
|
151
|
+
this.deviceData.manufacturer === '' ||
|
|
152
|
+
(this.#platform === undefined && typeof this.deviceData?.hkPairingCode !== 'string' && this.deviceData.hkPairingCode === '') ||
|
|
153
|
+
(this.#platform === undefined &&
|
|
154
|
+
typeof this.deviceData?.hkUsername !== 'string' &&
|
|
155
|
+
new RegExp(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/).test(this.deviceData.hkUsername) === false)
|
|
156
|
+
) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// If we do not have an existing accessory object, create a new one
|
|
161
|
+
if (this.accessory === undefined && this.#platform !== undefined) {
|
|
162
|
+
// Create HomeBridge platform accessory
|
|
163
|
+
this.accessory = new this.#platform.platformAccessory(
|
|
164
|
+
this.deviceData.description,
|
|
165
|
+
this.hap.uuid.generate(HomeKitDevice.PLUGIN_NAME + '_' + this.deviceData.uuid),
|
|
166
|
+
);
|
|
167
|
+
this.#platform.registerPlatformAccessories(HomeKitDevice.PLUGIN_NAME, HomeKitDevice.PLATFORM_NAME, [this.accessory]);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (this.accessory === undefined && this.#platform === undefined) {
|
|
171
|
+
// Create HAP-NodeJS libray accessory
|
|
172
|
+
// We're using our previous parameters to generate the uuid, rather than the 'new' way we do for Homebridge
|
|
173
|
+
this.accessory = new this.hap.Accessory(
|
|
174
|
+
accessoryName,
|
|
175
|
+
this.hap.uuid.generate(
|
|
176
|
+
'hap-nodejs:accessories:' + this.deviceData.manufacturer.toLowerCase() + '_' + this.deviceData.serial_number,
|
|
177
|
+
),
|
|
178
|
+
);
|
|
179
|
+
this.accessory.username = this.deviceData.hkUsername;
|
|
180
|
+
this.accessory.pincode = this.deviceData.hkPairingCode;
|
|
181
|
+
this.accessory.category = accessoryCategory;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Setup accessory information
|
|
185
|
+
let informationService = this.accessory.getService(this.hap.Service.AccessoryInformation);
|
|
186
|
+
if (informationService !== undefined) {
|
|
187
|
+
informationService.updateCharacteristic(this.hap.Characteristic.Manufacturer, this.deviceData.manufacturer);
|
|
188
|
+
informationService.updateCharacteristic(this.hap.Characteristic.Model, this.deviceData.model);
|
|
189
|
+
informationService.updateCharacteristic(this.hap.Characteristic.SerialNumber, this.deviceData.serial_number);
|
|
190
|
+
informationService.updateCharacteristic(this.hap.Characteristic.FirmwareRevision, this.deviceData.software_version);
|
|
191
|
+
}
|
|
192
|
+
informationService.updateCharacteristic(this.hap.Characteristic.Name, this.deviceData.description);
|
|
193
|
+
|
|
194
|
+
// Setup our history service if module has been defined and requested to be active for this device
|
|
195
|
+
if (typeof HomeKitDevice?.HISTORY === 'function' && this.historyService === undefined && useHistoryService === true) {
|
|
196
|
+
this.historyService = new HomeKitDevice.HISTORY(this.accessory, this.log, this.hap, {});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (typeof this.addServices === 'function') {
|
|
200
|
+
try {
|
|
201
|
+
let postSetupDetails = await this.addServices();
|
|
202
|
+
if (this?.log?.info) {
|
|
203
|
+
this.log.info('Setup %s %s as "%s"', this.deviceData.manufacturer, this.deviceData.model, this.deviceData.description);
|
|
204
|
+
if (this.historyService?.EveHome !== undefined) {
|
|
205
|
+
this.log.info(' += EveHome support as "%s"', this.historyService.EveHome.evetype);
|
|
206
|
+
}
|
|
207
|
+
if (typeof postSetupDetails === 'object') {
|
|
208
|
+
postSetupDetails.forEach((output) => {
|
|
209
|
+
if (this?.log?.info) {
|
|
210
|
+
this.log.info(' += %s', output);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
this?.log?.error && this.log.error('addServices call for device "%s" failed. Error was', this.deviceData.description, error);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// if we have a valid EventEmitter and we have not previously setup an message event handler, do so now
|
|
221
|
+
if (this.#eventEmitter !== undefined && this.#eventEmitter.listenerCount(this.deviceData.uuid) === 0) {
|
|
222
|
+
this.#eventEmitter.addListener(this.deviceData.uuid, this.#message.bind(this));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Perform an initial update using current data
|
|
226
|
+
this.update(this.deviceData, true);
|
|
227
|
+
|
|
228
|
+
// If using HAP-NodeJS library, publish accessory on local network
|
|
229
|
+
if (this.#platform === undefined && this.accessory !== undefined) {
|
|
230
|
+
if (this?.log?.info) {
|
|
231
|
+
this.log.info(' += Advertising as "%s"', accessoryName);
|
|
232
|
+
this.log.info(' += Pairing code is "%s"', this.accessory.pincode);
|
|
233
|
+
}
|
|
234
|
+
this.accessory.publish({
|
|
235
|
+
username: this.accessory.username,
|
|
236
|
+
pincode: this.accessory.pincode,
|
|
237
|
+
category: this.accessory.category,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async remove() {
|
|
243
|
+
this?.log?.warn && this.log.warn('Device "%s" has been removed', this.deviceData.description);
|
|
244
|
+
|
|
245
|
+
if (this.#eventEmitter === undefined && typeof this.deviceData?.uuid === 'string' && this.deviceData.uuid !== '') {
|
|
246
|
+
// Remove listener for 'messages'
|
|
247
|
+
this.#eventEmitter.removeAllListeners(this.deviceData.uuid);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (typeof this.removeServices === 'function') {
|
|
251
|
+
try {
|
|
252
|
+
await this.removeServices();
|
|
253
|
+
} catch (error) {
|
|
254
|
+
this?.log?.error && this.log.error('removeServices call for device "%s" failed. Error was', this.deviceData.description, error);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (this.accessory !== undefined && this.#platform !== undefined) {
|
|
259
|
+
// Unregister the accessory from Homebridge
|
|
260
|
+
this.#platform.unregisterPlatformAccessories(HomeKitDevice.PLUGIN_NAME, HomeKitDevice.PLATFORM_NAME, [this.accessory]);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (this.accessory !== undefined && this.#platform === undefined) {
|
|
264
|
+
// Unpublish the accessory from HAP
|
|
265
|
+
this.accessory.unpublish();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.deviceData = {};
|
|
269
|
+
this.accessory = undefined;
|
|
270
|
+
this.historyService = undefined;
|
|
271
|
+
this.hap = undefined;
|
|
272
|
+
this.log = undefined;
|
|
273
|
+
this.#platform = undefined;
|
|
274
|
+
this.#eventEmitter = undefined;
|
|
275
|
+
|
|
276
|
+
// Do we destroy this object??
|
|
277
|
+
// this = null;
|
|
278
|
+
// delete this;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async update(deviceData, forceUpdate) {
|
|
282
|
+
if (typeof deviceData !== 'object' || typeof forceUpdate !== 'boolean') {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Updated data may only contain selected fields, so we'll handle that here by taking our internally stored data
|
|
287
|
+
// and merge with the updates to ensure we have a complete data object
|
|
288
|
+
Object.entries(this.deviceData).forEach(([key, value]) => {
|
|
289
|
+
if (typeof deviceData[key] === 'undefined') {
|
|
290
|
+
// Updated data doesn't have this key, so add it to our internally stored data
|
|
291
|
+
deviceData[key] = value;
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Check updated device data with our internally stored data. Flag if changes between the two
|
|
296
|
+
let changedData = false;
|
|
297
|
+
Object.keys(deviceData).forEach((key) => {
|
|
298
|
+
if (JSON.stringify(deviceData[key]) !== JSON.stringify(this.deviceData[key])) {
|
|
299
|
+
changedData = true;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// If we have any changed data OR we've been requested to force an update, do so here
|
|
304
|
+
if ((changedData === true || forceUpdate === true) && this.accessory !== undefined) {
|
|
305
|
+
let informationService = this.accessory.getService(this.hap.Service.AccessoryInformation);
|
|
306
|
+
if (informationService !== undefined) {
|
|
307
|
+
// Update details associated with the accessory
|
|
308
|
+
// ie: Name, Manufacturer, Model, Serial # and firmware version
|
|
309
|
+
if (typeof deviceData?.description === 'string' && deviceData.description !== this.deviceData.description) {
|
|
310
|
+
// Update serial number on the HomeKit accessory
|
|
311
|
+
informationService.updateCharacteristic(this.hap.Characteristic.Name, this.deviceData.description);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (
|
|
315
|
+
typeof deviceData?.manufacturer === 'string' &&
|
|
316
|
+
deviceData.manufacturer !== '' &&
|
|
317
|
+
deviceData.manufacturer !== this.deviceData.manufacturer
|
|
318
|
+
) {
|
|
319
|
+
// Update serial number on the HomeKit accessory
|
|
320
|
+
informationService.updateCharacteristic(this.hap.Characteristic.Manufacturer, this.deviceData.manufacturer);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (typeof deviceData?.model === 'string' && deviceData.model !== '' && deviceData.model !== this.deviceData.model) {
|
|
324
|
+
// Update serial number on the HomeKit accessory
|
|
325
|
+
informationService.updateCharacteristic(this.hap.Characteristic.Model, this.deviceData.model);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (
|
|
329
|
+
typeof deviceData?.serial_number === 'string' &&
|
|
330
|
+
deviceData.serial_number !== '' &&
|
|
331
|
+
deviceData.serial_number !== this.deviceData.serial_number
|
|
332
|
+
) {
|
|
333
|
+
// Update serial number on the HomeKit accessory
|
|
334
|
+
informationService.updateCharacteristic(this.hap.Characteristic.SerialNumber, this.deviceData.serial_number);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (
|
|
338
|
+
typeof deviceData?.software_version === 'string' &&
|
|
339
|
+
deviceData.software_version !== '' &&
|
|
340
|
+
deviceData.software_version !== this.deviceData.software_version
|
|
341
|
+
) {
|
|
342
|
+
// Update software version on the HomeKit accessory
|
|
343
|
+
informationService.updateCharacteristic(this.hap.Characteristic.FirmwareRevision, this.deviceData.software_version);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (typeof deviceData?.online === 'boolean' && deviceData.online !== this.deviceData.online) {
|
|
348
|
+
// Output device online/offline status
|
|
349
|
+
if (deviceData.online === false && this?.log?.warn) {
|
|
350
|
+
this.log.warn('Device "%s" is offline', this.deviceData.description);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (deviceData.online === true && this?.log?.success) {
|
|
354
|
+
this.log.success('Device "%s" is online', this.deviceData.description);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (typeof this.updateServices === 'function') {
|
|
359
|
+
try {
|
|
360
|
+
await this.updateServices(deviceData); // Pass updated data on for accessory to process as it needs
|
|
361
|
+
} catch (error) {
|
|
362
|
+
this?.log?.error && this.log.error('updateServices call for device "%s" failed. Error was', this.deviceData.description, error);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Finally, update our internally stored data with the new data
|
|
367
|
+
// eslint-disable-next-line no-undef
|
|
368
|
+
this.deviceData = structuredClone(deviceData);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async set(values) {
|
|
373
|
+
if (
|
|
374
|
+
typeof values !== 'object' ||
|
|
375
|
+
this.#eventEmitter === undefined ||
|
|
376
|
+
typeof this.deviceData?.uuid !== 'string' ||
|
|
377
|
+
this.deviceData.uuid === ''
|
|
378
|
+
) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Send event with data to set
|
|
383
|
+
this.#eventEmitter.emit(HomeKitDevice.SET, this.deviceData.uuid, values);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async get(values) {
|
|
387
|
+
if (
|
|
388
|
+
typeof values !== 'object' ||
|
|
389
|
+
this.#eventEmitter === undefined ||
|
|
390
|
+
typeof this.deviceData?.uuid !== 'string' ||
|
|
391
|
+
this.deviceData.uuid === ''
|
|
392
|
+
) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Send event with data to get
|
|
397
|
+
// Once get has completed, we'll get an eevent back with the requested data
|
|
398
|
+
this.#eventEmitter.emit(HomeKitDevice.GET, this.deviceData.uuid, values);
|
|
399
|
+
|
|
400
|
+
// This should always return, but we probably should put in a timeout?
|
|
401
|
+
let results = await EventEmitter.once(this.#eventEmitter, HomeKitDevice.GET + '->' + this.deviceData.uuid);
|
|
402
|
+
return results?.[0];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async #message(type, message) {
|
|
406
|
+
switch (type) {
|
|
407
|
+
case HomeKitDevice.ADD: {
|
|
408
|
+
// Got message for device add
|
|
409
|
+
if (typeof message?.name === 'string' && typeof message?.category === 'number' && typeof message?.history === 'boolean') {
|
|
410
|
+
this.add(message.name, message.category, message.history);
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
case HomeKitDevice.UPDATE: {
|
|
416
|
+
// Got some device data, so process any updates
|
|
417
|
+
this.update(message, false);
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
case HomeKitDevice.REMOVE: {
|
|
422
|
+
// Got message for device removal
|
|
423
|
+
this.remove();
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
default: {
|
|
428
|
+
// This is not a message we know about, so pass onto accessory for it to perform any processing
|
|
429
|
+
if (typeof this.messageServices === 'function') {
|
|
430
|
+
try {
|
|
431
|
+
await this.messageServices(type, message);
|
|
432
|
+
} catch (error) {
|
|
433
|
+
this?.log?.error &&
|
|
434
|
+
this.log.error('messageServices call for device "%s" failed. Error was', this.deviceData.description, error);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|