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 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.5 (2024/09/13)
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 12/9/2024
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
@@ -1,7 +1,7 @@
1
1
  // Nest Cam with Floodlight
2
2
  // Part of homebridge-nest-accfactory
3
3
  //
4
- // Code version 12/9/2024
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 11/9/2024
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.id = undefined; // No session ID yet
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.id = undefined; // Not an active session anymore
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 !== null) {
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.id = undefined; // Not an active session anymore
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 !== null) {
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.StartPlayback');
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.id,
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.id !== undefined && this.#protobufNexusTalk !== undefined) {
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.id,
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 === null || this.#socket.readyState !== 'open' || (type !== PacketType.HELLO && this.#authorised === false)) {
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.id = decodedMessage.sessionId;
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.id);
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(this.host); // try reconnection
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.id !== null && decodedMessage.reason === 'USER_ENDED_SESSION') {
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(this.host); // try reconnection to existing host
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 on "%s"', decodedMessage.deviceId);
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 on "%s"', decodedMessage.device_id);
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(host)
12
- // streamer.close(stopStreamFirst)
11
+ // streamer.connect()
12
+ // streamer.close()
13
13
  // streamer.talkingAudio(talkingData)
14
14
  // streamer.update(deviceData) <- call super after
15
15
  //
16
- // Code version 11/9/2024
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.host === 'string' && this.host !== '') {
156
- if (typeof this.connect === 'function') {
157
- this?.log?.debug && this.log.debug('Started buffering from "%s"', this.host);
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.host === 'string' && this.host !== '') {
205
- // We do not have an active socket connection, so startup connection to host
206
- if (typeof this.connect === 'function') {
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.host,
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.host === 'string' && this.host !== '') {
245
- // We do not have an active socket connection, so startup connection to host
246
- if (typeof this.connect === 'function') {
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.host, sessionID);
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 (typeof this.#outputs[sessionID] === 'object') {
267
- this?.log?.debug && this.log.debug('Stopped recording stream from "%s"', this.host);
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 to host
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(true);
266
+ this.close();
274
267
  }
275
268
  }
276
269
 
277
270
  stopLiveStream(sessionID) {
278
271
  // Request to stop an active live stream
279
- if (typeof this.#outputs[sessionID] === 'object') {
280
- this?.log?.debug && this.log.debug('Stopped live stream from "%s"', this.host);
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 to host
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(true);
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.host);
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 to host
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(true);
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(true); // as offline or streaming not enabled, close socket
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(this.host); // Connect to host for stream
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",
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",