@apocaliss92/scrypted-reolink-native 0.1.12 → 0.1.14
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/main.nodejs.js +1 -1
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/camera.ts +1 -5
- package/src/common.ts +92 -36
- package/src/stream-utils.ts +2 -2
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/src/camera.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ReolinkBaichuanApi } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
|
|
2
2
|
import sdk, { MediaObject, ObjectsDetected, RequestPictureOptions, ResponsePictureOptions, ScryptedInterface, Setting } from "@scrypted/sdk";
|
|
3
3
|
import { UrlMediaStreamOptions } from "../../scrypted/plugins/rtsp/src/rtsp";
|
|
4
4
|
import {
|
|
@@ -6,10 +6,6 @@ import {
|
|
|
6
6
|
} from "./common";
|
|
7
7
|
import { createBaichuanApi } from './connect';
|
|
8
8
|
import ReolinkNativePlugin from "./main";
|
|
9
|
-
import {
|
|
10
|
-
buildVideoStreamOptionsFromRtspRtmp,
|
|
11
|
-
fetchVideoStreamOptionsFromApi
|
|
12
|
-
} from './stream-utils';
|
|
13
9
|
|
|
14
10
|
export const moToB64 = async (mo: MediaObject) => {
|
|
15
11
|
const bufferImage = await sdk.mediaManager.convertMediaObjectToBuffer(mo, 'image/jpeg');
|
package/src/common.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DeviceCapabilities, PtzCommand, PtzPreset, ReolinkBaichuanApi, ReolinkSimpleEvent } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
|
|
1
|
+
import type { DeviceCapabilities, PtzCommand, PtzPreset, ReolinkBaichuanApi, ReolinkSimpleEvent, StreamSamplingSelection } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
|
|
2
2
|
import sdk, { BinarySensor, Brightness, Camera, Device, DeviceProvider, Intercom, MediaObject, MediaStreamUrl, ObjectDetectionTypes, ObjectDetector, ObjectsDetected, OnOff, PanTiltZoom, PanTiltZoomCommand, RequestMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, SettingValue, VideoCamera, VideoTextOverlay, VideoTextOverlays } from "@scrypted/sdk";
|
|
3
3
|
import { StorageSettings } from "@scrypted/sdk/storage-settings";
|
|
4
4
|
import type { UrlMediaStreamOptions } from "../../scrypted/plugins/rtsp/src/rtsp";
|
|
@@ -10,7 +10,7 @@ import ReolinkNativePlugin from "./main";
|
|
|
10
10
|
import { ReolinkNativeNvrDevice } from "./nvr";
|
|
11
11
|
import { ReolinkPtzPresets } from "./presets";
|
|
12
12
|
import {
|
|
13
|
-
|
|
13
|
+
buildVideoStreamOptions,
|
|
14
14
|
createRfc4571MediaObjectFromStreamManager,
|
|
15
15
|
expectedVideoTypeFromUrlMediaStreamOptions,
|
|
16
16
|
isNativeStreamId,
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
StreamManager
|
|
20
20
|
} from "./stream-utils";
|
|
21
21
|
import { getDeviceInterfaces, updateDeviceInfo } from "./utils";
|
|
22
|
+
import path from 'path';
|
|
22
23
|
|
|
23
24
|
export type CameraType = 'battery' | 'regular';
|
|
24
25
|
|
|
@@ -238,38 +239,6 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
|
|
|
238
239
|
type: 'boolean',
|
|
239
240
|
hide: true,
|
|
240
241
|
},
|
|
241
|
-
// snapshotCacheMinutes: {
|
|
242
|
-
// title: "Snapshot Cache Minutes",
|
|
243
|
-
// subgroup: 'Advanced',
|
|
244
|
-
// description: "Return a cached snapshot if taken within the last N minutes.",
|
|
245
|
-
// type: "number",
|
|
246
|
-
// defaultValue: 60,
|
|
247
|
-
// hide: true,
|
|
248
|
-
// },
|
|
249
|
-
batteryUpdateIntervalMinutes: {
|
|
250
|
-
title: "Battery Update Interval (minutes)",
|
|
251
|
-
subgroup: 'Advanced',
|
|
252
|
-
description: "How often to wake up the camera and update battery status and snapshot (default: 60 minutes).",
|
|
253
|
-
type: "number",
|
|
254
|
-
defaultValue: 60,
|
|
255
|
-
hide: true,
|
|
256
|
-
},
|
|
257
|
-
lowThresholdBatteryRecording: {
|
|
258
|
-
title: "Low Threshold Battery Recording (%)",
|
|
259
|
-
subgroup: 'Recording',
|
|
260
|
-
description: "Battery level threshold below which recording is disabled (default: 15%).",
|
|
261
|
-
type: "number",
|
|
262
|
-
defaultValue: 15,
|
|
263
|
-
hide: true,
|
|
264
|
-
},
|
|
265
|
-
highThresholdBatteryRecording: {
|
|
266
|
-
title: "High Threshold Battery Recording (%)",
|
|
267
|
-
subgroup: 'Recording',
|
|
268
|
-
description: "Battery level threshold above which recording is enabled (default: 35%).",
|
|
269
|
-
type: "number",
|
|
270
|
-
defaultValue: 35,
|
|
271
|
-
hide: true,
|
|
272
|
-
},
|
|
273
242
|
// Regular camera specific
|
|
274
243
|
dispatchEvents: {
|
|
275
244
|
subgroup: 'Advanced',
|
|
@@ -479,6 +448,47 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
|
|
|
479
448
|
logger.log(`PTZ presets: delete ok (presetId=${presetId})`);
|
|
480
449
|
},
|
|
481
450
|
},
|
|
451
|
+
batteryUpdateIntervalMinutes: {
|
|
452
|
+
title: "Battery Update Interval (minutes)",
|
|
453
|
+
subgroup: 'Advanced',
|
|
454
|
+
description: "How often to wake up the camera and update battery status and snapshot (default: 60 minutes).",
|
|
455
|
+
type: "number",
|
|
456
|
+
defaultValue: 60,
|
|
457
|
+
hide: true,
|
|
458
|
+
},
|
|
459
|
+
lowThresholdBatteryRecording: {
|
|
460
|
+
title: "Low Threshold Battery Recording (%)",
|
|
461
|
+
subgroup: 'Recording',
|
|
462
|
+
description: "Battery level threshold below which recording is disabled (default: 15%).",
|
|
463
|
+
type: "number",
|
|
464
|
+
defaultValue: 15,
|
|
465
|
+
hide: true,
|
|
466
|
+
},
|
|
467
|
+
highThresholdBatteryRecording: {
|
|
468
|
+
title: "High Threshold Battery Recording (%)",
|
|
469
|
+
subgroup: 'Recording',
|
|
470
|
+
description: "Battery level threshold above which recording is enabled (default: 35%).",
|
|
471
|
+
type: "number",
|
|
472
|
+
defaultValue: 35,
|
|
473
|
+
hide: true,
|
|
474
|
+
},
|
|
475
|
+
diagnosticsOutputPath: {
|
|
476
|
+
title: "Diagnostics Output Path",
|
|
477
|
+
subgroup: 'Diagnostics',
|
|
478
|
+
description: "Directory where diagnostics files will be saved (default: plugin volume).",
|
|
479
|
+
type: "string",
|
|
480
|
+
defaultValue: path.join(process.env.SCRYPTED_PLUGIN_VOLUME, 'diagnostics', this.name),
|
|
481
|
+
},
|
|
482
|
+
diagnosticsRun: {
|
|
483
|
+
subgroup: 'Diagnostics',
|
|
484
|
+
title: 'Run Diagnostics',
|
|
485
|
+
description: 'Run all diagnostics and save results to the output path.',
|
|
486
|
+
type: 'button',
|
|
487
|
+
immediate: true,
|
|
488
|
+
onPut: async () => {
|
|
489
|
+
await this.runDiagnostics();
|
|
490
|
+
},
|
|
491
|
+
},
|
|
482
492
|
});
|
|
483
493
|
|
|
484
494
|
ptzPresets = new ReolinkPtzPresets(this);
|
|
@@ -556,6 +566,16 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
|
|
|
556
566
|
onClose: async () => {
|
|
557
567
|
// Reset client state on close
|
|
558
568
|
// The base class already handles cleanup
|
|
569
|
+
// Resubscribe to events after reconnection
|
|
570
|
+
// Use setTimeout to allow the connection to be re-established first
|
|
571
|
+
setTimeout(async () => {
|
|
572
|
+
try {
|
|
573
|
+
await this.subscribeToEvents();
|
|
574
|
+
} catch (e) {
|
|
575
|
+
const logger = this.getBaichuanLogger();
|
|
576
|
+
logger.warn('Failed to resubscribe to events after reconnection', e);
|
|
577
|
+
}
|
|
578
|
+
}, 1000);
|
|
559
579
|
},
|
|
560
580
|
onSimpleEvent: this.onSimpleEvent,
|
|
561
581
|
getEventSubscriptionEnabled: () => this.isEventDispatchEnabled?.() ?? false,
|
|
@@ -571,6 +591,42 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
|
|
|
571
591
|
return this.name || 'Camera';
|
|
572
592
|
}
|
|
573
593
|
|
|
594
|
+
private async runDiagnostics(): Promise<void> {
|
|
595
|
+
const logger = this.getBaichuanLogger();
|
|
596
|
+
const outputPath = this.storageSettings.values.diagnosticsOutputPath || process.env.SCRYPTED_PLUGIN_VOLUME || "";
|
|
597
|
+
|
|
598
|
+
if (!outputPath) {
|
|
599
|
+
throw new Error('Diagnostics output path is required');
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const channel = this.storageSettings.values.rtspChannel || 0;
|
|
603
|
+
const durationSeconds = 15;
|
|
604
|
+
const selection: StreamSamplingSelection = {
|
|
605
|
+
kinds: ['native'],
|
|
606
|
+
profiles: ['main', 'ext', 'sub'],
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
logger.log(`Starting diagnostics with parameters: outDir=${outputPath}, channel=${channel}, durationSeconds=${durationSeconds}, selection=${JSON.stringify(selection)}`);
|
|
610
|
+
|
|
611
|
+
try {
|
|
612
|
+
const api = await this.ensureClient();
|
|
613
|
+
|
|
614
|
+
const result = await api.runAllDiagnosticsConsecutively({
|
|
615
|
+
outDir: outputPath,
|
|
616
|
+
channel,
|
|
617
|
+
durationSeconds,
|
|
618
|
+
selection,
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
logger.log(`Diagnostics completed successfully. Output directory: ${result.runDir}`);
|
|
622
|
+
logger.log(`Diagnostics file: ${result.diagnosticsPath}`);
|
|
623
|
+
logger.log(`Streams directory: ${result.streamsDir}`);
|
|
624
|
+
} catch (e) {
|
|
625
|
+
logger.error('Failed to run diagnostics', e);
|
|
626
|
+
throw e;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
574
630
|
protected async onBeforeCleanup(): Promise<void> {
|
|
575
631
|
// Unsubscribe from events if needed
|
|
576
632
|
if (this.onSimpleEvent && this.baichuanApi) {
|
|
@@ -1278,7 +1334,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
|
|
|
1278
1334
|
|
|
1279
1335
|
const client = await this.ensureClient();
|
|
1280
1336
|
|
|
1281
|
-
const { ipAddress, rtspChannel
|
|
1337
|
+
const { ipAddress, rtspChannel } = this.storageSettings.values;
|
|
1282
1338
|
|
|
1283
1339
|
try {
|
|
1284
1340
|
await this.ensureNetPortCache();
|
|
@@ -1289,7 +1345,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
|
|
|
1289
1345
|
}
|
|
1290
1346
|
|
|
1291
1347
|
try {
|
|
1292
|
-
streams = await
|
|
1348
|
+
streams = await buildVideoStreamOptions(
|
|
1293
1349
|
{
|
|
1294
1350
|
client,
|
|
1295
1351
|
ipAddress,
|
package/src/stream-utils.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ReolinkBaichuanApi,
|
|
3
|
-
StreamProfile,
|
|
4
3
|
ScryptedRfc4571TcpServer,
|
|
4
|
+
StreamProfile,
|
|
5
5
|
VideoType,
|
|
6
6
|
} from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
|
|
7
7
|
|
|
@@ -97,7 +97,7 @@ export async function fetchVideoStreamOptionsFromApi(
|
|
|
97
97
|
return streams;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export async function
|
|
100
|
+
export async function buildVideoStreamOptions(
|
|
101
101
|
props: {
|
|
102
102
|
client: ReolinkBaichuanApi,
|
|
103
103
|
ipAddress: string,
|