homebridge-nest-accfactory 0.2.2 → 0.2.3
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 +4 -0
- package/README.md +10 -5
- package/dist/HomeKitDevice.js +19 -60
- package/dist/HomeKitHistory.js +63 -67
- package/dist/camera.js +81 -57
- package/dist/doorbell.js +2 -2
- package/dist/index.js +1 -1
- package/dist/nexustalk.js +4 -4
- package/dist/protect.js +15 -43
- package/dist/streamer.js +8 -7
- package/dist/system.js +73 -29
- package/dist/thermostat.js +6 -18
- package/dist/webrtc.js +31 -8
- package/package.json +11 -10
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 10/11/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -321,10 +321,11 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
321
321
|
return;
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
-
// Build our ffmpeg command string for
|
|
324
|
+
// Build our ffmpeg command string for the liveview video/audio stream
|
|
325
325
|
let commandLine = [
|
|
326
326
|
'-hide_banner',
|
|
327
327
|
'-nostats',
|
|
328
|
+
'-use_wallclock_as_timestamps 1',
|
|
328
329
|
'-fflags +discardcorrupt',
|
|
329
330
|
'-max_delay 500000',
|
|
330
331
|
'-flags low_delay',
|
|
@@ -337,10 +338,22 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
337
338
|
this.deviceData.audio_enabled === true &&
|
|
338
339
|
this.controller.recordingManagement.recordingManagementService.getCharacteristic(this.hap.Characteristic.RecordingAudioActive)
|
|
339
340
|
.value === this.hap.Characteristic.RecordingAudioActive.ENABLE &&
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
this.streamer?.codecs?.audio === 'aac' &&
|
|
342
|
+
this.deviceData?.ffmpeg?.libfdk_aac === true
|
|
342
343
|
) {
|
|
343
|
-
//
|
|
344
|
+
// Audio data only on extra pipe created in spawn command
|
|
345
|
+
commandLine.push('-f aac -i pipe:3');
|
|
346
|
+
includeAudio = true;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (
|
|
350
|
+
this.deviceData.audio_enabled === true &&
|
|
351
|
+
this.controller.recordingManagement.recordingManagementService.getCharacteristic(this.hap.Characteristic.RecordingAudioActive)
|
|
352
|
+
.value === this.hap.Characteristic.RecordingAudioActive.ENABLE &&
|
|
353
|
+
this.streamer?.codecs?.audio === 'opus' &&
|
|
354
|
+
this.deviceData?.ffmpeg?.libopus === true
|
|
355
|
+
) {
|
|
356
|
+
// Audio data only on extra pipe created in spawn command
|
|
344
357
|
commandLine.push('-i pipe:3');
|
|
345
358
|
includeAudio = true;
|
|
346
359
|
}
|
|
@@ -367,11 +380,11 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
367
380
|
'-filter:v fps=fps=' + this.#recordingConfig.videoCodec.resolution[2],
|
|
368
381
|
'-g:v ' + (this.#recordingConfig.videoCodec.resolution[2] * this.#recordingConfig.videoCodec.parameters.iFrameInterval) / 1000,
|
|
369
382
|
'-b:v ' + this.#recordingConfig.videoCodec.parameters.bitRate + 'k',
|
|
383
|
+
'-bufsize ' + 2 * this.#recordingConfig.videoCodec.parameters.bitRate + 'k',
|
|
370
384
|
'-fps_mode passthrough',
|
|
371
|
-
'-movflags frag_keyframe+empty_moov+default_base_moof',
|
|
372
385
|
'-reset_timestamps 1',
|
|
373
386
|
'-video_track_timescale 90000',
|
|
374
|
-
'-
|
|
387
|
+
'-movflags frag_keyframe+empty_moov+default_base_moof',
|
|
375
388
|
);
|
|
376
389
|
|
|
377
390
|
// We have seperate video and audio streams that need to be muxed together if audio enabled
|
|
@@ -390,23 +403,26 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
390
403
|
|
|
391
404
|
commandLine.push('-f mp4 pipe:1'); // output to stdout in mp4
|
|
392
405
|
|
|
393
|
-
|
|
394
|
-
|
|
406
|
+
// Start our ffmpeg recording process and stream from our streamer
|
|
407
|
+
// video is pipe #1
|
|
408
|
+
// audio is pipe #3 if including audio
|
|
409
|
+
this?.log?.debug &&
|
|
410
|
+
this.log.debug(
|
|
411
|
+
'ffmpeg process for recording stream from "%s" will be called using the following commandline',
|
|
412
|
+
this.deviceData.description,
|
|
413
|
+
commandLine.join(' ').toString(),
|
|
414
|
+
);
|
|
415
|
+
let ffmpegRecording = child_process.spawn(this.deviceData.ffmpeg.binary, commandLine.join(' ').split(' '), {
|
|
395
416
|
env: process.env,
|
|
396
417
|
stdio: ['pipe', 'pipe', 'pipe', includeAudio === true ? 'pipe' : ''],
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
this.#hkSessions[sessionID].video = this.#hkSessions[sessionID].ffmpeg.stdin; // Video data on stdio pipe for ffmpeg
|
|
400
|
-
this.#hkSessions[sessionID].audio = this.#hkSessions[sessionID]?.ffmpeg?.stdio?.[3]
|
|
401
|
-
? this.#hkSessions[sessionID].ffmpeg.stdio[3]
|
|
402
|
-
: null; // Audio data on extra pipe for ffmpeg or null if audio recording disabled
|
|
418
|
+
});
|
|
403
419
|
|
|
404
420
|
// Process FFmpeg output and parse out the fMP4 stream it's generating for HomeKit Secure Video.
|
|
405
421
|
let mp4FragmentData = [];
|
|
406
|
-
|
|
407
|
-
|
|
422
|
+
let mp4boxes = [];
|
|
423
|
+
let eventEmitter = new EventEmitter();
|
|
408
424
|
|
|
409
|
-
|
|
425
|
+
ffmpegRecording.stdout.on('data', (data) => {
|
|
410
426
|
// Process the mp4 data from our socket connection and convert into mp4 fragment boxes we need
|
|
411
427
|
mp4FragmentData = mp4FragmentData.length === 0 ? data : Buffer.concat([mp4FragmentData, data]);
|
|
412
428
|
while (mp4FragmentData.length >= 8) {
|
|
@@ -419,13 +435,13 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
419
435
|
}
|
|
420
436
|
|
|
421
437
|
// Add it to our queue to be pushed out through the generator function.
|
|
422
|
-
if (
|
|
423
|
-
|
|
438
|
+
if (Array.isArray(mp4boxes) === true && eventEmitter !== undefined) {
|
|
439
|
+
mp4boxes.push({
|
|
424
440
|
header: mp4FragmentData.slice(0, 8),
|
|
425
441
|
type: mp4FragmentData.slice(4, 8).toString(),
|
|
426
442
|
data: mp4FragmentData.slice(8, boxSize),
|
|
427
443
|
});
|
|
428
|
-
|
|
444
|
+
eventEmitter.emit(MP4BOX);
|
|
429
445
|
}
|
|
430
446
|
|
|
431
447
|
// Remove the section of data we've just processed from our buffer
|
|
@@ -433,38 +449,38 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
433
449
|
}
|
|
434
450
|
});
|
|
435
451
|
|
|
436
|
-
|
|
452
|
+
ffmpegRecording.on('exit', (code, signal) => {
|
|
437
453
|
if (signal !== 'SIGKILL' || signal === null) {
|
|
438
454
|
this?.log?.error &&
|
|
439
455
|
this.log.error('ffmpeg recording process for "%s" stopped unexpectedly. Exit code was "%s"', this.deviceData.description, code);
|
|
440
456
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
this.#hkSessions[sessionID]
|
|
457
|
+
|
|
458
|
+
if (this.#hkSessions?.[sessionID] !== undefined) {
|
|
459
|
+
delete this.#hkSessions[sessionID];
|
|
444
460
|
}
|
|
445
461
|
});
|
|
446
462
|
|
|
447
463
|
// eslint-disable-next-line no-unused-vars
|
|
448
|
-
|
|
464
|
+
ffmpegRecording.on('error', (error) => {
|
|
449
465
|
// Empty
|
|
450
466
|
});
|
|
451
467
|
|
|
452
|
-
// ffmpeg
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
// Monitor ffmpeg output while testing. Use 'ffmpeg as a debug option'
|
|
468
|
+
// ffmpeg console output is via stderr
|
|
469
|
+
ffmpegRecording.stderr.on('data', (data) => {
|
|
470
|
+
if (data.toString().includes('frame=') === false && this.deviceData?.ffmpeg?.debug === true) {
|
|
471
|
+
// Monitor ffmpeg output
|
|
457
472
|
this?.log?.debug && this.log.debug(data.toString());
|
|
458
473
|
}
|
|
459
474
|
});
|
|
460
|
-
*/
|
|
461
475
|
|
|
476
|
+
// Start the appropriate streamer
|
|
462
477
|
this.streamer !== undefined &&
|
|
463
|
-
this.streamer.startRecordStream(
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
478
|
+
this.streamer.startRecordStream(sessionID, ffmpegRecording.stdin, ffmpegRecording?.stdio?.[3] ? ffmpegRecording.stdio[3] : null);
|
|
479
|
+
|
|
480
|
+
// Store our ffmpeg sessions
|
|
481
|
+
this.#hkSessions[sessionID] = {};
|
|
482
|
+
this.#hkSessions[sessionID].eventEmitter = eventEmitter;
|
|
483
|
+
this.#hkSessions[sessionID].ffmpeg = ffmpegRecording; // Store ffmpeg process ID
|
|
468
484
|
|
|
469
485
|
this?.log?.info &&
|
|
470
486
|
this.log.info('Started recording from "%s" %s', this.deviceData.description, includeAudio === false ? 'without audio' : '');
|
|
@@ -473,26 +489,19 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
473
489
|
// HAP-NodeJS cancels this async generator function when recording completes also
|
|
474
490
|
let segment = [];
|
|
475
491
|
for (;;) {
|
|
476
|
-
if (
|
|
477
|
-
this.#hkSessions?.[sessionID] === undefined ||
|
|
478
|
-
this.#hkSessions?.[sessionID]?.ffmpeg === undefined ||
|
|
479
|
-
this.#hkSessions?.[sessionID]?.mp4boxes === undefined ||
|
|
480
|
-
this.#hkSessions?.[sessionID]?.eventEmitter === undefined
|
|
481
|
-
) {
|
|
492
|
+
if (this.#hkSessions?.[sessionID] === undefined || this.#hkSessions?.[sessionID]?.ffmpeg === undefined) {
|
|
482
493
|
// Our session object is not present
|
|
483
494
|
// ffmpeg recorder process is not present
|
|
484
|
-
// the mp4box array is not present
|
|
485
|
-
// eventEmitter is not present
|
|
486
495
|
// so finish up the loop
|
|
487
496
|
break;
|
|
488
497
|
}
|
|
489
498
|
|
|
490
|
-
if (
|
|
499
|
+
if (mp4boxes?.length === 0 && eventEmitter !== undefined) {
|
|
491
500
|
// since the ffmpeg recorder process hasn't notified us of any mp4 fragment boxes, wait until there are some
|
|
492
|
-
await EventEmitter.once(
|
|
501
|
+
await EventEmitter.once(eventEmitter, MP4BOX);
|
|
493
502
|
}
|
|
494
503
|
|
|
495
|
-
let mp4box =
|
|
504
|
+
let mp4box = mp4boxes.shift();
|
|
496
505
|
if (typeof mp4box !== 'object') {
|
|
497
506
|
// Not an mp4 fragment box, so try again
|
|
498
507
|
continue;
|
|
@@ -789,19 +798,17 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
789
798
|
// Start our ffmpeg streaming process and stream from our streamer
|
|
790
799
|
// video is pipe #1
|
|
791
800
|
// audio is pipe #3 if including audio
|
|
801
|
+
this?.log?.debug &&
|
|
802
|
+
this.log.debug(
|
|
803
|
+
'ffmpeg process for live streaming from "%s" will be called using the following commandline',
|
|
804
|
+
this.deviceData.description,
|
|
805
|
+
commandLine.join(' ').toString(),
|
|
806
|
+
);
|
|
792
807
|
let ffmpegStreaming = child_process.spawn(this.deviceData.ffmpeg.binary, commandLine.join(' ').split(' '), {
|
|
793
808
|
env: process.env,
|
|
794
809
|
stdio: ['pipe', 'pipe', 'pipe', includeAudio === true ? 'pipe' : ''],
|
|
795
810
|
});
|
|
796
811
|
|
|
797
|
-
// ffmpeg console output is via stderr
|
|
798
|
-
ffmpegStreaming.stderr.on('data', (data) => {
|
|
799
|
-
if (data.toString().includes('frame=') === false) {
|
|
800
|
-
// Monitor ffmpeg output while testing. Use 'ffmpeg as a debug option'
|
|
801
|
-
this?.log?.debug && this.log.debug(data.toString());
|
|
802
|
-
}
|
|
803
|
-
});
|
|
804
|
-
|
|
805
812
|
ffmpegStreaming.on('exit', (code, signal) => {
|
|
806
813
|
if (signal !== 'SIGKILL' || signal === null) {
|
|
807
814
|
this?.log?.error &&
|
|
@@ -816,6 +823,14 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
816
823
|
}
|
|
817
824
|
});
|
|
818
825
|
|
|
826
|
+
// ffmpeg console output is via stderr
|
|
827
|
+
ffmpegStreaming.stderr.on('data', (data) => {
|
|
828
|
+
if (data.toString().includes('frame=') === false && this.deviceData?.ffmpeg?.debug === true) {
|
|
829
|
+
// Monitor ffmpeg output
|
|
830
|
+
this?.log?.debug && this.log.debug(data.toString());
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
|
|
819
834
|
// eslint-disable-next-line no-unused-vars
|
|
820
835
|
ffmpegStreaming.on('error', (error) => {
|
|
821
836
|
// Empty
|
|
@@ -875,6 +890,12 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
875
890
|
|
|
876
891
|
commandLine.push('-f data pipe:1');
|
|
877
892
|
|
|
893
|
+
this?.log?.debug &&
|
|
894
|
+
this.log.debug(
|
|
895
|
+
'ffmpeg process for talkback on "%s" will be called using the following commandline',
|
|
896
|
+
this.deviceData.description,
|
|
897
|
+
commandLine.join(' ').toString(),
|
|
898
|
+
);
|
|
878
899
|
ffmpegAudioTalkback = child_process.spawn(this.deviceData.ffmpeg.binary, commandLine.join(' ').split(' '), {
|
|
879
900
|
env: process.env,
|
|
880
901
|
});
|
|
@@ -900,7 +921,10 @@ export default class NestCamera extends HomeKitDevice {
|
|
|
900
921
|
|
|
901
922
|
// ffmpeg console output is via stderr
|
|
902
923
|
ffmpegAudioTalkback.stderr.on('data', (data) => {
|
|
903
|
-
|
|
924
|
+
if (data.toString().includes('frame=') === false && this.deviceData?.ffmpeg?.debug === true) {
|
|
925
|
+
// Monitor ffmpeg output
|
|
926
|
+
this?.log?.debug && this.log.debug(data.toString());
|
|
927
|
+
}
|
|
904
928
|
});
|
|
905
929
|
|
|
906
930
|
// Write out SDP configuration
|
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
|
|
4
|
+
// Code version 11/10/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -55,7 +55,7 @@ export default class NestDoorbell extends NestCamera {
|
|
|
55
55
|
// No longer required to have the switch service
|
|
56
56
|
// This is to handle Homebridge cached restored accessories and if configuration options have changed
|
|
57
57
|
this.accessory.removeService(this.switchService);
|
|
58
|
-
this.switchService
|
|
58
|
+
this.switchService = undefined;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Create extra details for output
|
package/dist/index.js
CHANGED
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 20/11/2024
|
|
9
9
|
// Mark Hulskamp
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
@@ -325,7 +325,7 @@ export default class NexusTalk extends Streamer {
|
|
|
325
325
|
requireConnectedCamera: false,
|
|
326
326
|
userAgent: USERAGENT,
|
|
327
327
|
deviceId: crypto.randomUUID(),
|
|
328
|
-
|
|
328
|
+
clientType: 'IOS',
|
|
329
329
|
authoriseRequest: authoriseRequest,
|
|
330
330
|
}),
|
|
331
331
|
).finish();
|
|
@@ -416,7 +416,7 @@ export default class NexusTalk extends Streamer {
|
|
|
416
416
|
this.connect(); // try reconnection
|
|
417
417
|
});
|
|
418
418
|
this.close(false); // Close existing socket
|
|
419
|
-
},
|
|
419
|
+
}, 10000);
|
|
420
420
|
|
|
421
421
|
// Handle video packet
|
|
422
422
|
if (decodedMessage?.channelId !== undefined && decodedMessage.channelId === this.video?.id) {
|
|
@@ -474,7 +474,7 @@ export default class NexusTalk extends Streamer {
|
|
|
474
474
|
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
475
475
|
//let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackBegin').decode(payload).toJSON();
|
|
476
476
|
this.audio.talking = true;
|
|
477
|
-
this?.log?.debug && this.log.debug(
|
|
477
|
+
this?.log?.debug && this.log.debug('Talking started on uuid "%s"', this.uuid);
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
480
|
|
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
|
|
4
|
+
// Code version 5/10/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -43,12 +43,6 @@ export default class NestProtect extends HomeKitDevice {
|
|
|
43
43
|
if (this.carbonMonoxideService === undefined) {
|
|
44
44
|
this.carbonMonoxideService = this.accessory.addService(this.hap.Service.CarbonMonoxideSensor, '', 1);
|
|
45
45
|
}
|
|
46
|
-
if (this.carbonMonoxideService.testCharacteristic(this.hap.Characteristic.StatusActive) === false) {
|
|
47
|
-
this.carbonMonoxideService.addCharacteristic(this.hap.Characteristic.StatusActive);
|
|
48
|
-
}
|
|
49
|
-
if (this.carbonMonoxideService.testCharacteristic(this.hap.Characteristic.StatusFault) === false) {
|
|
50
|
-
this.carbonMonoxideService.addCharacteristic(this.hap.Characteristic.StatusFault);
|
|
51
|
-
}
|
|
52
46
|
|
|
53
47
|
// Setup battery service if not already present on the accessory
|
|
54
48
|
this.batteryService = this.accessory.getService(this.hap.Service.Battery);
|
|
@@ -109,13 +103,12 @@ export default class NestProtect extends HomeKitDevice {
|
|
|
109
103
|
);
|
|
110
104
|
|
|
111
105
|
// Update smoke details
|
|
112
|
-
// If
|
|
106
|
+
// If protect isn't online, removed from base, replacement date past, report in HomeKit
|
|
113
107
|
this.smokeService.updateCharacteristic(
|
|
114
108
|
this.hap.Characteristic.StatusActive,
|
|
115
|
-
deviceData.online === true && deviceData.removed_from_base === false,
|
|
109
|
+
deviceData.online === true && deviceData.removed_from_base === false && Math.floor(Date.now() / 1000) <= deviceData.replacement_date,
|
|
116
110
|
);
|
|
117
111
|
|
|
118
|
-
// General fault if replacement date past or Nest isn't online or removed from base
|
|
119
112
|
this.smokeService.updateCharacteristic(
|
|
120
113
|
this.hap.Characteristic.StatusFault,
|
|
121
114
|
deviceData.online === true && deviceData.removed_from_base === false && Math.floor(Date.now() / 1000) <= deviceData.replacement_date
|
|
@@ -139,23 +132,9 @@ export default class NestProtect extends HomeKitDevice {
|
|
|
139
132
|
}
|
|
140
133
|
|
|
141
134
|
// Update carbon monoxide details
|
|
142
|
-
// If Nest isn't online or removed from base, report in HomeKit
|
|
143
|
-
this.carbonMonoxideService.updateCharacteristic(
|
|
144
|
-
this.hap.Characteristic.StatusActive,
|
|
145
|
-
deviceData.online === true && deviceData.removed_from_base === false,
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
// General fault if replacement date past or Nest isn't online or removed from base
|
|
149
|
-
this.carbonMonoxideService.updateCharacteristic(
|
|
150
|
-
this.hap.Characteristic.StatusFault,
|
|
151
|
-
deviceData.online === true && deviceData.removed_from_base === false && Math.floor(Date.now() / 1000) <= deviceData.replacement_date
|
|
152
|
-
? this.hap.Characteristic.StatusFault.NO_FAULT
|
|
153
|
-
: this.hap.Characteristic.StatusFault.GENERAL_FAULT,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
135
|
this.carbonMonoxideService.updateCharacteristic(
|
|
157
136
|
this.hap.Characteristic.CarbonMonoxideDetected,
|
|
158
|
-
deviceData.co_status
|
|
137
|
+
deviceData.co_status !== 0
|
|
159
138
|
? this.hap.Characteristic.CarbonMonoxideDetected.CO_LEVELS_ABNORMAL
|
|
160
139
|
: this.hap.Characteristic.CarbonMonoxideDetected.CO_LEVELS_NORMAL,
|
|
161
140
|
);
|
|
@@ -170,22 +149,11 @@ export default class NestProtect extends HomeKitDevice {
|
|
|
170
149
|
|
|
171
150
|
// Update motion service if present
|
|
172
151
|
if (this.motionService !== undefined) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
this.
|
|
176
|
-
this.
|
|
177
|
-
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
// General fault if replacement date past or Nest isn't online or removed from base
|
|
181
|
-
this.motionService.updateCharacteristic(
|
|
182
|
-
this.hap.Characteristic.StatusFault,
|
|
183
|
-
deviceData.online === true && deviceData.removed_from_base === false && Math.floor(Date.now() / 1000) <= deviceData.replacement_date
|
|
184
|
-
? this.hap.Characteristic.StatusFault.NO_FAULT
|
|
185
|
-
: this.hap.Characteristic.StatusFault.GENERAL_FAULT,
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
this.motionService.updateCharacteristic(this.hap.Characteristic.MotionDetected, deviceData.detected_motion === false);
|
|
152
|
+
this.motionService.updateCharacteristic(this.hap.Characteristic.MotionDetected, deviceData.detected_motion === true);
|
|
153
|
+
|
|
154
|
+
if (deviceData.detected_motion === true && this.deviceData.detected_motion === false) {
|
|
155
|
+
this?.log?.info && this.log.info('Motion detected in "%s"', deviceData.description);
|
|
156
|
+
}
|
|
189
157
|
|
|
190
158
|
// Log motion to history only if changed to previous recording
|
|
191
159
|
if (deviceData.detected_motion !== this.deviceData.detected_motion && typeof this.historyService?.addHistory === 'function') {
|
|
@@ -197,7 +165,11 @@ export default class NestProtect extends HomeKitDevice {
|
|
|
197
165
|
}
|
|
198
166
|
|
|
199
167
|
// Notify Eve App of device status changes if linked
|
|
200
|
-
if (
|
|
168
|
+
if (
|
|
169
|
+
this.deviceData.eveHistory === true &&
|
|
170
|
+
this.smokeService !== undefined &&
|
|
171
|
+
typeof this.historyService?.updateEveHome === 'function'
|
|
172
|
+
) {
|
|
201
173
|
// Update our internal data with properties Eve will need to process
|
|
202
174
|
this.deviceData.latest_alarm_test = deviceData.latest_alarm_test;
|
|
203
175
|
this.deviceData.self_test_in_progress = deviceData.self_test_in_progress;
|
|
@@ -210,7 +182,7 @@ export default class NestProtect extends HomeKitDevice {
|
|
|
210
182
|
}
|
|
211
183
|
|
|
212
184
|
#EveHomeGetcommand(EveHomeGetData) {
|
|
213
|
-
// Pass back extra data for Eve Smoke
|
|
185
|
+
// Pass back extra data for Eve Smoke onGet() to process command
|
|
214
186
|
// Data will already be an object, our only job is to add/modify to it
|
|
215
187
|
if (typeof EveHomeGetData === 'object') {
|
|
216
188
|
EveHomeGetData.lastalarmtest = this.deviceData.latest_alarm_test;
|
package/dist/streamer.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
//
|
|
18
18
|
// blankAudio - Buffer containing a blank audio segment for the type of audio being used
|
|
19
19
|
//
|
|
20
|
-
// Code version
|
|
20
|
+
// Code version 20/11/2024
|
|
21
21
|
// Mark Hulskamp
|
|
22
22
|
'use strict';
|
|
23
23
|
|
|
@@ -143,11 +143,7 @@ export default class Streamer {
|
|
|
143
143
|
if (output.type === 'live' || output.type === 'record') {
|
|
144
144
|
let packet = output.buffer.shift();
|
|
145
145
|
if (packet?.type === 'video' && typeof output?.video?.write === 'function') {
|
|
146
|
-
|
|
147
|
-
// If this is missing, add on beginning of data packet
|
|
148
|
-
if (packet.data.indexOf(H264NALSTARTCODE) !== 0) {
|
|
149
|
-
packet.data = Buffer.concat([H264NALSTARTCODE, packet.data]);
|
|
150
|
-
}
|
|
146
|
+
packet.data = Buffer.concat([H264NALSTARTCODE, packet.data]);
|
|
151
147
|
output.video.write(packet.data);
|
|
152
148
|
}
|
|
153
149
|
if (packet?.type === 'audio' && typeof output?.audio?.write === 'function') {
|
|
@@ -361,9 +357,14 @@ export default class Streamer {
|
|
|
361
357
|
return;
|
|
362
358
|
}
|
|
363
359
|
|
|
360
|
+
if (data.indexOf(H264NALSTARTCODE) === 0) {
|
|
361
|
+
// Strip H264 start code from input buffer. We'll handle this later
|
|
362
|
+
data = data.subarray(H264NALSTARTCODE.length);
|
|
363
|
+
}
|
|
364
|
+
|
|
364
365
|
Object.values(this.#outputs).forEach((output) => {
|
|
365
366
|
output.buffer.push({
|
|
366
|
-
time: Date.now(), // Timestamp of when
|
|
367
|
+
time: Date.now(), // Timestamp of when this was added to buffer
|
|
367
368
|
type: type,
|
|
368
369
|
data: data,
|
|
369
370
|
});
|