homebridge-nest-accfactory 0.0.5 → 0.0.6
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 +5 -1
- package/dist/camera.js +2 -1
- package/dist/floodlight.js +2 -2
- package/dist/nexustalk.js +25 -19
- package/dist/streamer.js +28 -40
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,11 @@ All notable changes to `homebridge-nest-accfactory` will be documented in this f
|
|
|
6
6
|
|
|
7
7
|
Currently all releases are considered 'alpha' status, where things may or may not be working. Use at your own risk :-)
|
|
8
8
|
|
|
9
|
-
## v0.0.
|
|
9
|
+
## v0.0.6 (2024-09-14)
|
|
10
|
+
|
|
11
|
+
- Fix for two/way audio starting on non-enabled HKSV camera/doorbells
|
|
12
|
+
|
|
13
|
+
## v0.0.5 (2024-09-13)
|
|
10
14
|
|
|
11
15
|
- General code cleanup and bug fixes
|
|
12
16
|
- External dependancy reductions, dropped pbf and axios libraries
|
package/dist/camera.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Nest Cameras
|
|
2
2
|
// Part of homebridge-nest-accfactory
|
|
3
3
|
//
|
|
4
|
-
// Code version
|
|
4
|
+
// Code version 13/9/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -33,6 +33,7 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
33
33
|
controller = undefined; // HomeKit Camera/Doorbell controller service
|
|
34
34
|
streamer = undefined; // Streamer object for live/recording stream
|
|
35
35
|
motionServices = undefined; // Object of Camera/Doorbell motion sensor(s)
|
|
36
|
+
batteryService = undefined; // If a camera has a battery
|
|
36
37
|
operatingModeService = undefined; // Link to camera/doorbell operating mode service
|
|
37
38
|
personTimer = undefined; // Cooldown timer for person/face events
|
|
38
39
|
motionTimer = undefined; // Cooldown timer for motion events
|
package/dist/floodlight.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Nest Cam with Floodlight
|
|
2
2
|
// Part of homebridge-nest-accfactory
|
|
3
3
|
//
|
|
4
|
-
// Code version
|
|
4
|
+
// Code version 13/9/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -48,7 +48,7 @@ export default class NestFloodlight extends NestCamera {
|
|
|
48
48
|
if (value !== this.deviceData.light_brightness) {
|
|
49
49
|
this.set({ light_brightness: value });
|
|
50
50
|
|
|
51
|
-
this?.log?.info && this.log.info('Floodlight brightness on "%s" was set to "%s %"', this.deviceData.description);
|
|
51
|
+
this?.log?.info && this.log.info('Floodlight brightness on "%s" was set to "%s %"', this.deviceData.description, value);
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
|
package/dist/nexustalk.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
//
|
|
6
6
|
// Credit to https://github.com/Brandawg93/homebridge-nest-cam for the work on the Nest Camera comms code on which this is based
|
|
7
7
|
//
|
|
8
|
-
// Code version
|
|
8
|
+
// Code version 14/9/2024
|
|
9
9
|
// Mark Hulskamp
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
@@ -59,11 +59,11 @@ const PacketType = {
|
|
|
59
59
|
export default class NexusTalk extends Streamer {
|
|
60
60
|
token = undefined;
|
|
61
61
|
tokenType = undefined;
|
|
62
|
-
id = undefined; // Session ID
|
|
63
62
|
pingTimer = undefined; // Timer object for ping interval
|
|
64
63
|
stalledTimer = undefined; // Timer object for no received data
|
|
65
64
|
video = {}; // Video stream details
|
|
66
65
|
audio = {}; // Audio stream details
|
|
66
|
+
host = ''; // Host to connect to or connected too
|
|
67
67
|
|
|
68
68
|
// Internal data only for this class
|
|
69
69
|
#protobufNexusTalk = undefined; // Protobuf for NexusTalk
|
|
@@ -71,6 +71,7 @@ export default class NexusTalk extends Streamer {
|
|
|
71
71
|
#packets = []; // Incoming packets
|
|
72
72
|
#messages = []; // Incoming messages
|
|
73
73
|
#authorised = false; // Have we been authorised
|
|
74
|
+
#id = undefined; // Session ID
|
|
74
75
|
|
|
75
76
|
constructor(deviceData, options) {
|
|
76
77
|
super(deviceData, options);
|
|
@@ -98,7 +99,7 @@ export default class NexusTalk extends Streamer {
|
|
|
98
99
|
this.pingTimer = clearInterval(this.pingTimer);
|
|
99
100
|
this.stalledTimer = clearInterval(this.stalledTimer);
|
|
100
101
|
|
|
101
|
-
this
|
|
102
|
+
this.#id = undefined; // No session ID yet
|
|
102
103
|
|
|
103
104
|
if (this.online === true && this.videoEnabled === true) {
|
|
104
105
|
if (typeof host === 'undefined' || host === null) {
|
|
@@ -134,7 +135,7 @@ export default class NexusTalk extends Streamer {
|
|
|
134
135
|
this.#authorised = false; // Since connection close, we can't be authorised anymore
|
|
135
136
|
this.#socket = undefined; // Clear socket object
|
|
136
137
|
this.connected = false;
|
|
137
|
-
this
|
|
138
|
+
this.#id = undefined; // Not an active session anymore
|
|
138
139
|
|
|
139
140
|
if (hadError === true && this.haveOutputs() === true) {
|
|
140
141
|
// We still have either active buffering occuring or output streams running
|
|
@@ -147,7 +148,7 @@ export default class NexusTalk extends Streamer {
|
|
|
147
148
|
|
|
148
149
|
close(stopStreamFirst) {
|
|
149
150
|
// Close an authenicated socket stream gracefully
|
|
150
|
-
if (this.#socket !==
|
|
151
|
+
if (this.#socket !== undefined) {
|
|
151
152
|
if (stopStreamFirst === true) {
|
|
152
153
|
// Send a notifcation to nexus we're finished playback
|
|
153
154
|
this.#stopNexusData();
|
|
@@ -157,7 +158,7 @@ export default class NexusTalk extends Streamer {
|
|
|
157
158
|
|
|
158
159
|
this.connected = false;
|
|
159
160
|
this.#socket = undefined;
|
|
160
|
-
this
|
|
161
|
+
this.#id = undefined; // Not an active session anymore
|
|
161
162
|
this.#packets = [];
|
|
162
163
|
this.#messages = [];
|
|
163
164
|
}
|
|
@@ -171,11 +172,16 @@ export default class NexusTalk extends Streamer {
|
|
|
171
172
|
// access token has changed so re-authorise
|
|
172
173
|
this.token = deviceData.apiAccess.token;
|
|
173
174
|
|
|
174
|
-
if (this.#socket !==
|
|
175
|
+
if (this.#socket !== undefined) {
|
|
175
176
|
this.#Authenticate(true); // Update authorisation only if connected
|
|
176
177
|
}
|
|
177
178
|
}
|
|
178
179
|
|
|
180
|
+
if (this.host !== deviceData.streaming_host) {
|
|
181
|
+
this.host = deviceData.streaming_host;
|
|
182
|
+
this?.log?.debug && this.log.debug('New host has been requested for connection. Host requested is "%s"', this.host);
|
|
183
|
+
}
|
|
184
|
+
|
|
179
185
|
// Let our parent handle the remaining updates
|
|
180
186
|
super.update(deviceData);
|
|
181
187
|
}
|
|
@@ -183,12 +189,12 @@ export default class NexusTalk extends Streamer {
|
|
|
183
189
|
talkingAudio(talkingData) {
|
|
184
190
|
// Encode audio packet for sending to camera
|
|
185
191
|
if (typeof talkingData === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
186
|
-
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.
|
|
192
|
+
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.AudioPayload');
|
|
187
193
|
if (TraitMap !== null) {
|
|
188
194
|
let encodedData = TraitMap.encode(
|
|
189
195
|
TraitMap.fromObject({
|
|
190
196
|
payload: talkingData,
|
|
191
|
-
sessionId: this
|
|
197
|
+
sessionId: this.#id,
|
|
192
198
|
codec: 'SPEEX',
|
|
193
199
|
sampleRate: 16000,
|
|
194
200
|
}),
|
|
@@ -227,12 +233,12 @@ export default class NexusTalk extends Streamer {
|
|
|
227
233
|
}
|
|
228
234
|
|
|
229
235
|
#stopNexusData() {
|
|
230
|
-
if (this
|
|
236
|
+
if (this.#id !== undefined && this.#protobufNexusTalk !== undefined) {
|
|
231
237
|
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.StopPlayback');
|
|
232
238
|
if (TraitMap !== null) {
|
|
233
239
|
let encodedData = TraitMap.encode(
|
|
234
240
|
TraitMap.fromObject({
|
|
235
|
-
sessionId: this
|
|
241
|
+
sessionId: this.#id,
|
|
236
242
|
}),
|
|
237
243
|
).finish();
|
|
238
244
|
this.#sendMessage(PacketType.STOP_PLAYBACK, encodedData);
|
|
@@ -241,7 +247,7 @@ export default class NexusTalk extends Streamer {
|
|
|
241
247
|
}
|
|
242
248
|
|
|
243
249
|
#sendMessage(type, data) {
|
|
244
|
-
if (this.#socket
|
|
250
|
+
if (this.#socket?.readyState !== 'open' || (type !== PacketType.HELLO && this.#authorised === false)) {
|
|
245
251
|
// We're not connect and/or authorised yet, so 'cache' message for processing once this occurs
|
|
246
252
|
this.#messages.push({ type: type, data: data });
|
|
247
253
|
return;
|
|
@@ -358,11 +364,11 @@ export default class NexusTalk extends Streamer {
|
|
|
358
364
|
});
|
|
359
365
|
|
|
360
366
|
// Since this is the beginning of playback, clear any active buffers contents
|
|
361
|
-
this
|
|
367
|
+
this.#id = decodedMessage.sessionId;
|
|
362
368
|
this.#packets = [];
|
|
363
369
|
this.#messages = [];
|
|
364
370
|
|
|
365
|
-
this?.log?.debug && this.log.debug('Playback started from "%s" with session ID "%s"', this.host, this
|
|
371
|
+
this?.log?.debug && this.log.debug('Playback started from "%s" with session ID "%s"', this.host, this.#id);
|
|
366
372
|
}
|
|
367
373
|
}
|
|
368
374
|
|
|
@@ -381,7 +387,7 @@ export default class NexusTalk extends Streamer {
|
|
|
381
387
|
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
|
|
382
388
|
this.#socket &&
|
|
383
389
|
this.#socket.on('close', () => {
|
|
384
|
-
this.connect(
|
|
390
|
+
this.connect(); // try reconnection
|
|
385
391
|
});
|
|
386
392
|
this.close(false); // Close existing socket
|
|
387
393
|
}, 8000);
|
|
@@ -405,7 +411,7 @@ export default class NexusTalk extends Streamer {
|
|
|
405
411
|
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
406
412
|
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.PlaybackEnd').decode(payload).toJSON();
|
|
407
413
|
|
|
408
|
-
if (this
|
|
414
|
+
if (this.#id !== undefined && decodedMessage.reason === 'USER_ENDED_SESSION') {
|
|
409
415
|
// Normal playback ended ie: when we stopped playback
|
|
410
416
|
this?.log?.debug && this.log.debug('Playback ended on "%s"', this.host);
|
|
411
417
|
}
|
|
@@ -418,7 +424,7 @@ export default class NexusTalk extends Streamer {
|
|
|
418
424
|
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
|
|
419
425
|
this.#socket &&
|
|
420
426
|
this.#socket.on('close', () => {
|
|
421
|
-
this.connect(
|
|
427
|
+
this.connect(); // try reconnection to existing host
|
|
422
428
|
});
|
|
423
429
|
this.close(false); // Close existing socket
|
|
424
430
|
}
|
|
@@ -443,7 +449,7 @@ export default class NexusTalk extends Streamer {
|
|
|
443
449
|
// Decode talk begin packet
|
|
444
450
|
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
445
451
|
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackBegin').decode(payload).toJSON();
|
|
446
|
-
this?.log?.debug && this.log.debug('Talkback started
|
|
452
|
+
this?.log?.debug && this.log.debug('Talkback started to uuid "%s" with id of "%s"', this.uuid, decodedMessage.deviceId);
|
|
447
453
|
}
|
|
448
454
|
}
|
|
449
455
|
|
|
@@ -451,7 +457,7 @@ export default class NexusTalk extends Streamer {
|
|
|
451
457
|
// Decode talk end packet
|
|
452
458
|
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
453
459
|
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackEnd').decode(payload).toJSON();
|
|
454
|
-
this?.log?.debug && this.log.debug('Talkback ended
|
|
460
|
+
this?.log?.debug && this.log.debug('Talkback ended from uuid "%s" with id of "%s"', this.uuid, decodedMessage.deviceId);
|
|
455
461
|
}
|
|
456
462
|
}
|
|
457
463
|
|
package/dist/streamer.js
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
//
|
|
9
9
|
// The following functions should be overriden in your class which extends this
|
|
10
10
|
//
|
|
11
|
-
// streamer.connect(
|
|
12
|
-
// streamer.close(
|
|
11
|
+
// streamer.connect()
|
|
12
|
+
// streamer.close()
|
|
13
13
|
// streamer.talkingAudio(talkingData)
|
|
14
14
|
// streamer.update(deviceData) <- call super after
|
|
15
15
|
//
|
|
16
|
-
// Code version
|
|
16
|
+
// Code version 13/9/2024
|
|
17
17
|
// Mark Hulskamp
|
|
18
18
|
'use strict';
|
|
19
19
|
|
|
@@ -38,7 +38,6 @@ export default class Streamer {
|
|
|
38
38
|
videoEnabled = undefined; // Video stream on camera enabled or not
|
|
39
39
|
audioEnabled = undefined; // Audio from camera enabled or not
|
|
40
40
|
online = undefined; // Camera online or not
|
|
41
|
-
host = ''; // Host to connect to or connected too
|
|
42
41
|
uuid = undefined; // UUID of the device connecting
|
|
43
42
|
connected = false; // Streamer connected to endpoint
|
|
44
43
|
|
|
@@ -152,11 +151,9 @@ export default class Streamer {
|
|
|
152
151
|
startBuffering() {
|
|
153
152
|
if (this.#outputs?.buffer === undefined) {
|
|
154
153
|
// No active buffer session, start connection to streamer
|
|
155
|
-
if (this.connected === false && typeof this.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
this.connect(this.host);
|
|
159
|
-
}
|
|
154
|
+
if (this.connected === false && typeof this.connect === 'function') {
|
|
155
|
+
this?.log?.debug && this.log.debug('Started buffering for uuid "%s"', this.uuid);
|
|
156
|
+
this.connect();
|
|
160
157
|
}
|
|
161
158
|
|
|
162
159
|
this.#outputs.buffer = {
|
|
@@ -201,11 +198,9 @@ export default class Streamer {
|
|
|
201
198
|
});
|
|
202
199
|
}
|
|
203
200
|
|
|
204
|
-
if (this.connected === false && typeof this.
|
|
205
|
-
// We do not have an active
|
|
206
|
-
|
|
207
|
-
this.connect(this.host);
|
|
208
|
-
}
|
|
201
|
+
if (this.connected === false && typeof this.connect === 'function') {
|
|
202
|
+
// We do not have an active connection, so startup connection
|
|
203
|
+
this.connect();
|
|
209
204
|
}
|
|
210
205
|
|
|
211
206
|
// Add video/audio streams for our output loop to handle outputting to
|
|
@@ -220,8 +215,8 @@ export default class Streamer {
|
|
|
220
215
|
// finally, we've started live stream
|
|
221
216
|
this?.log?.debug &&
|
|
222
217
|
this.log.debug(
|
|
223
|
-
'Started live stream from "%s" %s "%s"',
|
|
224
|
-
this.
|
|
218
|
+
'Started live stream from uuid "%s" %s "%s"',
|
|
219
|
+
this.uuid,
|
|
225
220
|
talkbackStream !== null && typeof talkbackStream === 'object' ? 'with two-way audio and sesssion id of' : 'and sesssion id of',
|
|
226
221
|
sessionID,
|
|
227
222
|
);
|
|
@@ -241,11 +236,9 @@ export default class Streamer {
|
|
|
241
236
|
});
|
|
242
237
|
}
|
|
243
238
|
|
|
244
|
-
if (this.connected === false && typeof this.
|
|
245
|
-
// We do not have an active
|
|
246
|
-
|
|
247
|
-
this.connect(this.host);
|
|
248
|
-
}
|
|
239
|
+
if (this.connected === false && typeof this.connect === 'function') {
|
|
240
|
+
// We do not have an active connection, so startup connection
|
|
241
|
+
this.connect();
|
|
249
242
|
}
|
|
250
243
|
|
|
251
244
|
// Add video/audio streams for our output loop to handle outputting to
|
|
@@ -258,44 +251,44 @@ export default class Streamer {
|
|
|
258
251
|
};
|
|
259
252
|
|
|
260
253
|
// Finally we've started the recording stream
|
|
261
|
-
this?.log?.debug && this.log.debug('Started recording stream from "%s" with sesison id of "%s"', this.
|
|
254
|
+
this?.log?.debug && this.log.debug('Started recording stream from uuid "%s" with sesison id of "%s"', this.uuid, sessionID);
|
|
262
255
|
}
|
|
263
256
|
|
|
264
257
|
stopRecordStream(sessionID) {
|
|
265
258
|
// Request to stop a recording stream
|
|
266
|
-
if (
|
|
267
|
-
this?.log?.debug && this.log.debug('Stopped recording stream from "%s"', this.
|
|
259
|
+
if (this.#outputs?.[sessionID] !== undefined) {
|
|
260
|
+
this?.log?.debug && this.log.debug('Stopped recording stream from uuid "%s"', this.uuid);
|
|
268
261
|
delete this.#outputs[sessionID];
|
|
269
262
|
}
|
|
270
263
|
|
|
271
|
-
// If we have no more output streams active, we'll close the connection
|
|
264
|
+
// If we have no more output streams active, we'll close the connection
|
|
272
265
|
if (Object.keys(this.#outputs).length === 0 && typeof this.close === 'function') {
|
|
273
|
-
this.close(
|
|
266
|
+
this.close();
|
|
274
267
|
}
|
|
275
268
|
}
|
|
276
269
|
|
|
277
270
|
stopLiveStream(sessionID) {
|
|
278
271
|
// Request to stop an active live stream
|
|
279
|
-
if (
|
|
280
|
-
this?.log?.debug && this.log.debug('Stopped live stream from "%s"', this.
|
|
272
|
+
if (this.#outputs?.[sessionID] !== undefined) {
|
|
273
|
+
this?.log?.debug && this.log.debug('Stopped live stream from uuid "%s"', this.uuid);
|
|
281
274
|
delete this.#outputs[sessionID];
|
|
282
275
|
}
|
|
283
276
|
|
|
284
|
-
// If we have no more output streams active, we'll close the connection
|
|
277
|
+
// If we have no more output streams active, we'll close the connection
|
|
285
278
|
if (Object.keys(this.#outputs).length === 0 && typeof this.close === 'function') {
|
|
286
|
-
this.close(
|
|
279
|
+
this.close();
|
|
287
280
|
}
|
|
288
281
|
}
|
|
289
282
|
|
|
290
283
|
stopBuffering() {
|
|
291
284
|
if (this.#outputs?.buffer !== undefined) {
|
|
292
|
-
this?.log?.debug && this.log.debug('Stopped buffering from "%s"', this.
|
|
285
|
+
this?.log?.debug && this.log.debug('Stopped buffering from uuid "%s"', this.uuid);
|
|
293
286
|
delete this.#outputs.buffer;
|
|
294
287
|
}
|
|
295
288
|
|
|
296
|
-
// If we have no more output streams active, we'll close the connection
|
|
289
|
+
// If we have no more output streams active, we'll close the connection
|
|
297
290
|
if (Object.keys(this.#outputs).length === 0 && typeof this.close === 'function') {
|
|
298
|
-
this.close(
|
|
291
|
+
this.close();
|
|
299
292
|
}
|
|
300
293
|
}
|
|
301
294
|
|
|
@@ -304,11 +297,6 @@ export default class Streamer {
|
|
|
304
297
|
return;
|
|
305
298
|
}
|
|
306
299
|
|
|
307
|
-
if (this.host !== deviceData.streaming_host) {
|
|
308
|
-
this.host = deviceData.streaming_host;
|
|
309
|
-
this?.log?.debug && this.log.debug('New streaming host has been requested for connection. Host requested is "%s"', this.host);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
300
|
if (
|
|
313
301
|
this.online !== deviceData.online ||
|
|
314
302
|
this.videoEnabled !== deviceData.streaming_enabled ||
|
|
@@ -319,10 +307,10 @@ export default class Streamer {
|
|
|
319
307
|
this.videoEnabled = deviceData?.streaming_enabled === true;
|
|
320
308
|
this.audioEnabled = deviceData?.audio_enabled === true;
|
|
321
309
|
if ((this.online === false || this.videoEnabled === false || this.audioEnabled === false) && typeof this.close === 'function') {
|
|
322
|
-
this.close(
|
|
310
|
+
this.close(); // as offline or streaming not enabled, close streamer
|
|
323
311
|
}
|
|
324
312
|
if (this.online === true && this.videoEnabled === true && typeof this.connect === 'function') {
|
|
325
|
-
this.connect(
|
|
313
|
+
this.connect(); // Connect for stream
|
|
326
314
|
}
|
|
327
315
|
}
|
|
328
316
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"displayName": "Nest Accfactory",
|
|
3
3
|
"name": "homebridge-nest-accfactory",
|
|
4
4
|
"homepage": "https://github.com/n0rt0nthec4t/homebridge-nest-accfactory",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.6",
|
|
6
6
|
"description": "Homebridge support for Nest/Google devices including HomeKit Secure Video (HKSV) support for doorbells and cameras",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"author": "n0rt0nthec4t",
|