homebridge-nest-accfactory 0.0.6 → 0.2.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.
package/dist/doorbell.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Nest Doorbell(s)
2
2
  // Part of homebridge-nest-accfactory
3
3
  //
4
- // Code version 12/9/2024
4
+ // Code version 27/9/2024
5
5
  // Mark Hulskamp
6
6
  'use strict';
7
7
 
@@ -41,7 +41,7 @@ export default class NestDoorbell extends NestCamera {
41
41
  this.switchService.getCharacteristic(this.hap.Characteristic.On).onSet((value) => {
42
42
  if (value !== this.deviceData.indoor_chime_enabled) {
43
43
  // only change indoor chime status value if different than on-device
44
- this.set({ indoor_chime_enabled: value });
44
+ this.set({ uuid: this.deviceData.nest_google_uuid, indoor_chime_enabled: value });
45
45
 
46
46
  this?.log?.info && this.log.info('Indoor chime on "%s" was turned', this.deviceData.description, value === true ? 'on' : 'off');
47
47
  }
@@ -66,7 +66,9 @@ export default class NestDoorbell extends NestCamera {
66
66
  removeServices() {
67
67
  super.removeServices();
68
68
 
69
- this.doorbellTimer = clearTimeout(this.doorbellTimer);
69
+ clearTimeout(this.doorbellTimer);
70
+ this.doorbellTimer = undefined;
71
+
70
72
  if (this.switchService !== undefined) {
71
73
  this.accessory.removeService(this.switchService);
72
74
  }
@@ -1,7 +1,7 @@
1
1
  // Nest Cam with Floodlight
2
2
  // Part of homebridge-nest-accfactory
3
3
  //
4
- // Code version 13/9/2024
4
+ // Code version 27/9/2024
5
5
  // Mark Hulskamp
6
6
  'use strict';
7
7
 
@@ -38,7 +38,7 @@ export default class NestFloodlight extends NestCamera {
38
38
  // Setup set callback for this light service
39
39
  this.lightService.getCharacteristic(this.hap.Characteristic.On).onSet((value) => {
40
40
  if (value !== this.deviceData.light_enabled) {
41
- this.set({ light_enabled: value });
41
+ this.set({ uuid: this.deviceData.nest_google_uuid, light_enabled: value });
42
42
 
43
43
  this?.log?.info && this.log.info('Floodlight on "%s" was turned', this.deviceData.description, value === true ? 'on' : 'off');
44
44
  }
@@ -46,7 +46,7 @@ export default class NestFloodlight extends NestCamera {
46
46
 
47
47
  this.lightService.getCharacteristic(this.hap.Characteristic.Brightness).onSet((value) => {
48
48
  if (value !== this.deviceData.light_brightness) {
49
- this.set({ light_brightness: value });
49
+ this.set({ uuid: this.deviceData.nest_google_uuid, light_brightness: value });
50
50
 
51
51
  this?.log?.info && this.log.info('Floodlight brightness on "%s" was set to "%s %"', this.deviceData.description, value);
52
52
  }
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 14/9/2024
8
+ // Code version 29/9/2024
9
9
  // Mark Hulskamp
10
10
  'use strict';
11
11
 
@@ -55,15 +55,22 @@ const PacketType = {
55
55
  AUTHORIZE_REQUEST: 212,
56
56
  };
57
57
 
58
+ // Blank audio in AAC format, mono channel @48000
59
+ const AACMONO48000BLANK = Buffer.from([
60
+ 0xff, 0xf1, 0x4c, 0x40, 0x03, 0x9f, 0xfc, 0xde, 0x02, 0x00, 0x4c, 0x61, 0x76, 0x63, 0x35, 0x39, 0x2e, 0x31, 0x38, 0x2e, 0x31, 0x30, 0x30,
61
+ 0x00, 0x02, 0x30, 0x40, 0x0e,
62
+ ]);
63
+
58
64
  // nexusTalk object
59
65
  export default class NexusTalk extends Streamer {
60
66
  token = undefined;
61
67
  tokenType = undefined;
62
68
  pingTimer = undefined; // Timer object for ping interval
63
69
  stalledTimer = undefined; // Timer object for no received data
64
- video = {}; // Video stream details
65
- audio = {}; // Audio stream details
66
70
  host = ''; // Host to connect to or connected too
71
+ blankAudio = AACMONO48000BLANK;
72
+ video = {}; // Video stream details once connected
73
+ audio = {}; // Audio stream details once connected
67
74
 
68
75
  // Internal data only for this class
69
76
  #protobufNexusTalk = undefined; // Protobuf for NexusTalk
@@ -87,8 +94,15 @@ export default class NexusTalk extends Streamer {
87
94
  this.tokenType = deviceData?.apiAccess?.oauth2 !== undefined ? 'google' : 'nest';
88
95
  this.host = deviceData?.streaming_host; // Host we'll connect to
89
96
 
97
+ // Set our streamer codec types
98
+ this.codecs = {
99
+ video: 'h264',
100
+ audio: 'aac',
101
+ talk: 'speex',
102
+ };
103
+
90
104
  // If specified option to start buffering, kick off
91
- if (typeof options?.buffer === 'boolean' && options.buffer === true) {
105
+ if (options?.buffer === true) {
92
106
  this.startBuffering();
93
107
  }
94
108
  }
@@ -96,9 +110,10 @@ export default class NexusTalk extends Streamer {
96
110
  // Class functions
97
111
  connect(host) {
98
112
  // Clear any timers we have running
99
- this.pingTimer = clearInterval(this.pingTimer);
100
- this.stalledTimer = clearInterval(this.stalledTimer);
101
-
113
+ clearInterval(this.pingTimer);
114
+ clearTimeout(this.stalledTimer);
115
+ this.pingTimer = undefined;
116
+ this.stalledTimer = undefined;
102
117
  this.#id = undefined; // No session ID yet
103
118
 
104
119
  if (this.online === true && this.videoEnabled === true) {
@@ -107,7 +122,8 @@ export default class NexusTalk extends Streamer {
107
122
  host = this.host;
108
123
  }
109
124
 
110
- this?.log?.debug && this.log.debug('Starting connection to "%s"', host);
125
+ this.connected = false; // Starting connection
126
+ this?.log?.debug && this.log.debug('Connection started to "%s"', host);
111
127
 
112
128
  this.#socket = tls.connect({ host: host, port: 1443 }, () => {
113
129
  // Opened connection to Nexus server, so now need to authenticate ourselves
@@ -130,11 +146,13 @@ export default class NexusTalk extends Streamer {
130
146
  this.#socket.on('close', (hadError) => {
131
147
  this?.log?.debug && this.log.debug('Connection closed to "%s"', host);
132
148
 
133
- this.stalledTimer = clearTimeout(this.stalledTimer); // Clear stalled timer
134
- this.pingTimer = clearInterval(this.pingTimer); // Clear ping timer
149
+ clearInterval(this.pingTimer);
150
+ clearTimeout(this.stalledTimer);
151
+ this.pingTimer = undefined;
152
+ this.stalledTimer = undefined;
135
153
  this.#authorised = false; // Since connection close, we can't be authorised anymore
136
154
  this.#socket = undefined; // Clear socket object
137
- this.connected = false;
155
+ this.connected = undefined;
138
156
  this.#id = undefined; // Not an active session anymore
139
157
 
140
158
  if (hadError === true && this.haveOutputs() === true) {
@@ -156,11 +174,13 @@ export default class NexusTalk extends Streamer {
156
174
  this.#socket.destroy();
157
175
  }
158
176
 
159
- this.connected = false;
177
+ this.connected = undefined;
160
178
  this.#socket = undefined;
161
179
  this.#id = undefined; // Not an active session anymore
162
180
  this.#packets = [];
163
181
  this.#messages = [];
182
+ this.video = {};
183
+ this.audio = {};
164
184
  }
165
185
 
166
186
  update(deviceData) {
@@ -195,7 +215,7 @@ export default class NexusTalk extends Streamer {
195
215
  TraitMap.fromObject({
196
216
  payload: talkingData,
197
217
  sessionId: this.#id,
198
- codec: 'SPEEX',
218
+ codec: this.codecs.talk.toUpperCase(),
199
219
  sampleRate: 16000,
200
220
  }),
201
221
  ).finish();
@@ -345,20 +365,21 @@ export default class NexusTalk extends Streamer {
345
365
  let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.PlaybackBegin').decode(payload).toJSON();
346
366
  decodedMessage.channels.forEach((stream) => {
347
367
  // Find which channels match our video and audio streams
348
- if (stream.codecType === 'H264') {
368
+ if (stream.codecType === this.codecs.video.toUpperCase()) {
349
369
  this.video = {
350
- channel_id: stream.channelId,
351
- start_time: Date.now() + stream.startTime,
352
- sample_rate: stream.sampleRate,
353
- timestamp_delta: 0,
370
+ id: stream.channelId,
371
+ startTime: Date.now() + stream.startTime,
372
+ sampleRate: stream.sampleRate,
373
+ timeStamp: 0,
354
374
  };
355
375
  }
356
- if (stream.codecType === 'AAC' || stream.codecType === 'OPUS' || stream.codecType === 'SPEEX') {
376
+ if (stream.codecType === this.codecs.audio.toUpperCase()) {
357
377
  this.audio = {
358
- channel_id: stream.channelId,
359
- start_time: Date.now() + stream.startTime,
360
- sample_rate: stream.sampleRate,
361
- timestamp_delta: 0,
378
+ id: stream.channelId,
379
+ startTime: Date.now() + stream.startTime,
380
+ sampleRate: stream.sampleRate,
381
+ timeStamp: 0,
382
+ talking: false,
362
383
  };
363
384
  }
364
385
  });
@@ -380,9 +401,14 @@ export default class NexusTalk extends Streamer {
380
401
  // Setup up a timeout to monitor for no packets recieved in a certain period
381
402
  // If its trigger, we'll attempt to restart the stream and/or connection
382
403
  // <-- testing to see how often this occurs first
383
- this.stalledTimer = clearTimeout(this.stalledTimer);
404
+ clearTimeout(this.stalledTimer);
384
405
  this.stalledTimer = setTimeout(() => {
385
- this?.log?.debug && this.log.debug('We have not received any data from nexus in the past "%s" seconds. Attempting restart', 8);
406
+ this?.log?.debug &&
407
+ this.log.debug(
408
+ 'We have not received any data from nexus in the past "%s" seconds for uuid "%s". Attempting restart',
409
+ 10,
410
+ this.uuid,
411
+ );
386
412
 
387
413
  // Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
388
414
  this.#socket &&
@@ -393,15 +419,13 @@ export default class NexusTalk extends Streamer {
393
419
  }, 8000);
394
420
 
395
421
  // Handle video packet
396
- if (decodedMessage.channelId === this.video.channel_id) {
397
- this.video.timestamp_delta += decodedMessage.timestampDelta;
398
- this.addToOutput('video', this.video.start_time + this.video.timestamp_delta, Buffer.from(decodedMessage.payload, 'base64'));
422
+ if (decodedMessage?.channelId !== undefined && decodedMessage.channelId === this.video?.id) {
423
+ this.addToOutput('video', Buffer.from(decodedMessage.payload, 'base64'));
399
424
  }
400
425
 
401
426
  // Handle audio packet
402
- if (decodedMessage.channelId === this.audio.channel_id) {
403
- this.audio.timestamp_delta += decodedMessage.timestampDelta;
404
- this.addToOutput('audio', this.audio.start_time + this.audio.timestamp_delta, Buffer.from(decodedMessage.payload, 'base64'));
427
+ if (decodedMessage?.channelId !== undefined && decodedMessage.channelId === this.audio?.id) {
428
+ this.addToOutput('audio', Buffer.from(decodedMessage.payload, 'base64'));
405
429
  }
406
430
  }
407
431
  }
@@ -448,16 +472,18 @@ export default class NexusTalk extends Streamer {
448
472
  #handleTalkbackBegin(payload) {
449
473
  // Decode talk begin packet
450
474
  if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
451
- let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackBegin').decode(payload).toJSON();
452
- this?.log?.debug && this.log.debug('Talkback started to uuid "%s" with id of "%s"', this.uuid, decodedMessage.deviceId);
475
+ //let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackBegin').decode(payload).toJSON();
476
+ this.audio.talking = true;
477
+ this?.log?.debug && this.log.debug(Streamer.TALKINGSTART, this.uuid);
453
478
  }
454
479
  }
455
480
 
456
481
  #handleTalkbackEnd(payload) {
457
482
  // Decode talk end packet
458
483
  if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
459
- let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackEnd').decode(payload).toJSON();
460
- this?.log?.debug && this.log.debug('Talkback ended from uuid "%s" with id of "%s"', this.uuid, decodedMessage.deviceId);
484
+ //let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackEnd').decode(payload).toJSON();
485
+ this.audio.talking = false;
486
+ this?.log?.debug && this.log.debug('Talking ended on uuid "%s"', this.uuid);
461
487
  }
462
488
  }
463
489
 
@@ -497,7 +523,7 @@ export default class NexusTalk extends Streamer {
497
523
  }
498
524
 
499
525
  // Periodically send PING message to keep stream alive
500
- this.pingTimer = clearInterval(this.pingTimer);
526
+ clearInterval(this.pingTimer);
501
527
  this.pingTimer = setInterval(() => {
502
528
  this.#sendMessage(PacketType.PING, Buffer.alloc(0));
503
529
  }, PINGINTERVAL);
package/dist/protect.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Nest Protect
2
2
  // Part of homebridge-nest-accfactory
3
3
  //
4
- // Code version 12/9/2024
4
+ // Code version 27/9/2024
5
5
  // Mark Hulskamp
6
6
  'use strict';
7
7
 
@@ -233,7 +233,7 @@ export default class NestProtect extends HomeKitDevice {
233
233
  //this.log.info('Eve Smoke Alarm test', (EveHomeSetData.alarmtest === true ? 'start' : 'stop'));
234
234
  }
235
235
  if (typeof EveHomeSetData?.statusled === 'boolean') {
236
- this.set({ ntp_green_led_enable: EveHomeSetData.statusled });
236
+ this.set({ uuid: this.deviceData.nest_google_uuid, ntp_green_led_enable: EveHomeSetData.statusled });
237
237
  }
238
238
  }
239
239
  }