@apocaliss92/scrypted-reolink-native 0.3.17 → 0.4.1
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/.vscode/settings.json +1 -1
- package/dist/main.nodejs.js +1 -1
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/accessories/autotracking.ts +150 -0
- package/src/accessories/floodlight.ts +92 -0
- package/src/accessories/index.ts +7 -0
- package/src/accessories/motion-floodlight.ts +171 -0
- package/src/accessories/motion-siren.ts +165 -0
- package/src/accessories/pir-sensor.ts +138 -0
- package/src/accessories/siren.ts +63 -0
- package/src/baichuan-base.ts +863 -792
- package/src/camera.ts +3726 -2911
- package/src/intercom.ts +496 -476
- package/src/main.ts +378 -409
- package/src/multiFocal.ts +300 -270
- package/src/nvr.ts +588 -477
- package/src/stream-utils.ts +478 -427
- package/src/utils.ts +385 -1009
package/src/multiFocal.ts
CHANGED
|
@@ -1,307 +1,337 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
BatteryInfo,
|
|
3
|
+
DeviceCapabilities,
|
|
4
|
+
DualLensChannelAnalysis,
|
|
5
|
+
NativeVideoStreamVariant,
|
|
6
|
+
ReolinkBaichuanApi,
|
|
7
|
+
ReolinkSimpleEvent,
|
|
8
|
+
SleepStatus,
|
|
9
|
+
} from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
|
|
10
|
+
import sdk, {
|
|
11
|
+
Device,
|
|
12
|
+
DeviceProvider,
|
|
13
|
+
Reboot,
|
|
14
|
+
ScryptedDeviceType,
|
|
15
|
+
Settings,
|
|
16
|
+
} from "@scrypted/sdk";
|
|
3
17
|
import type { BaichuanConnectionConfig } from "./baichuan-base";
|
|
4
18
|
import { CameraType, ReolinkCamera } from "./camera";
|
|
5
19
|
import ReolinkNativePlugin from "./main";
|
|
6
20
|
import { ReolinkNativeNvrDevice } from "./nvr";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
import {
|
|
22
|
+
batteryCameraSuffix,
|
|
23
|
+
cameraSuffix,
|
|
24
|
+
getDeviceInterfaces,
|
|
25
|
+
} from "./utils";
|
|
26
|
+
|
|
27
|
+
export class ReolinkNativeMultiFocalDevice
|
|
28
|
+
extends ReolinkCamera
|
|
29
|
+
implements Settings, DeviceProvider, Reboot
|
|
30
|
+
{
|
|
31
|
+
plugin: ReolinkNativePlugin;
|
|
32
|
+
lensDevicesMap = new Map<string, ReolinkCamera>();
|
|
33
|
+
private channelToNativeIdMap = new Map<number, string>();
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
nativeId: string,
|
|
37
|
+
plugin: ReolinkNativePlugin,
|
|
38
|
+
type: CameraType,
|
|
39
|
+
nvrDevice?: ReolinkNativeNvrDevice,
|
|
40
|
+
) {
|
|
41
|
+
super(nativeId, plugin, { type, nvrDevice });
|
|
42
|
+
|
|
43
|
+
this.plugin = plugin;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected async onBeforeCleanup(): Promise<void> {
|
|
47
|
+
await this.unsubscribeFromAllEvents();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected getDeviceName(): string {
|
|
51
|
+
return this.name || "Multi-Focal Device";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getInterfaces(lensType?: NativeVideoStreamVariant) {
|
|
55
|
+
const logger = this.getBaichuanLogger();
|
|
56
|
+
const { multifocalInfo } = this.storageSettings.values;
|
|
57
|
+
const caps = await this.getAbilities();
|
|
58
|
+
|
|
59
|
+
let capabilities: DeviceCapabilities = { ...caps };
|
|
60
|
+
|
|
61
|
+
if (lensType) {
|
|
62
|
+
const channelInfo = (
|
|
63
|
+
multifocalInfo as DualLensChannelAnalysis
|
|
64
|
+
).channels.find((c) => c.variantType === lensType);
|
|
65
|
+
|
|
66
|
+
const hasPtz =
|
|
67
|
+
channelInfo?.hasPan || channelInfo?.hasTilt || channelInfo?.hasZoom;
|
|
68
|
+
|
|
69
|
+
capabilities = {
|
|
70
|
+
...capabilities,
|
|
71
|
+
hasPan: channelInfo.hasPan,
|
|
72
|
+
hasTilt: channelInfo.hasTilt,
|
|
73
|
+
hasZoom: channelInfo?.hasZoom,
|
|
74
|
+
hasPresets: channelInfo?.hasPresets || hasPtz,
|
|
75
|
+
hasIntercom: channelInfo?.hasIntercom,
|
|
76
|
+
hasPtz,
|
|
77
|
+
};
|
|
22
78
|
}
|
|
23
79
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
80
|
+
const { interfaces } = getDeviceInterfaces({
|
|
81
|
+
capabilities,
|
|
82
|
+
logger,
|
|
83
|
+
isLensDevice: !!lensType,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
logger.debug(
|
|
87
|
+
`Interfaces found for lens ${lensType}: ${JSON.stringify({ interfaces, capabilities, multifocalInfo, isLensDevice: !!lensType })}`,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return { interfaces, capabilities };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async reportDevices(): Promise<void> {
|
|
94
|
+
await super.reportDevices();
|
|
95
|
+
|
|
96
|
+
const logger = this.getBaichuanLogger();
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const api = await this.ensureClient();
|
|
100
|
+
const { username, password, ipAddress, uid, rtspChannel } =
|
|
101
|
+
this.storageSettings.values;
|
|
102
|
+
|
|
103
|
+
const { capabilities, objects, presets } =
|
|
104
|
+
await api.getDeviceCapabilities(rtspChannel);
|
|
105
|
+
const multifocalInfo = await api.getDualLensChannelInfo(rtspChannel, {
|
|
106
|
+
onNvr: !!this.nvrDevice,
|
|
107
|
+
});
|
|
108
|
+
logger.log(`Discovering ${multifocalInfo.channels.length} lenses`);
|
|
109
|
+
logger.debug({ multifocalInfo, capabilities });
|
|
110
|
+
|
|
111
|
+
this.storageSettings.values.multifocalInfo = multifocalInfo;
|
|
112
|
+
|
|
113
|
+
for (const channelInfo of multifocalInfo?.channels ?? []) {
|
|
114
|
+
const { channel, lensType, variantType } = channelInfo;
|
|
115
|
+
|
|
116
|
+
const name = `${this.name} - ${lensType}`;
|
|
117
|
+
const nativeId = `${this.nativeId}-${lensType}${this.isBattery ? batteryCameraSuffix : cameraSuffix}`;
|
|
118
|
+
|
|
119
|
+
this.channelToNativeIdMap.set(channel, nativeId);
|
|
120
|
+
const { interfaces, capabilities: deviceCapabilities } =
|
|
121
|
+
await this.getInterfaces();
|
|
122
|
+
|
|
123
|
+
const device: Device = {
|
|
124
|
+
providerNativeId: this.nativeId,
|
|
125
|
+
name,
|
|
126
|
+
nativeId,
|
|
127
|
+
info: {
|
|
128
|
+
...this.info,
|
|
129
|
+
metadata: {
|
|
130
|
+
channel,
|
|
131
|
+
lensType,
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
interfaces,
|
|
135
|
+
type: ScryptedDeviceType.Camera,
|
|
136
|
+
};
|
|
32
137
|
|
|
33
|
-
|
|
138
|
+
await sdk.deviceManager.onDeviceDiscovered(device);
|
|
34
139
|
|
|
35
|
-
|
|
36
|
-
|
|
140
|
+
logger.log(`Discovering lens ${lensType}`);
|
|
141
|
+
logger.debug(`${JSON.stringify({ interfaces, deviceCapabilities })}`);
|
|
37
142
|
|
|
38
|
-
|
|
143
|
+
const camera = await this.getDevice(nativeId);
|
|
39
144
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
hasTilt: channelInfo.hasTilt,
|
|
44
|
-
hasZoom: channelInfo?.hasZoom,
|
|
45
|
-
hasPresets: channelInfo?.hasPresets || hasPtz,
|
|
46
|
-
hasIntercom: channelInfo?.hasIntercom,
|
|
47
|
-
hasPtz,
|
|
48
|
-
};
|
|
145
|
+
if (!camera) {
|
|
146
|
+
logger.error(`Failed to get device ${nativeId}`);
|
|
147
|
+
continue;
|
|
49
148
|
}
|
|
50
149
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
150
|
+
camera.storageSettings.values.rtspChannel = channel;
|
|
151
|
+
camera.classes = objects;
|
|
152
|
+
camera.presets = presets;
|
|
153
|
+
camera.storageSettings.values.username = username;
|
|
154
|
+
camera.storageSettings.values.password = password;
|
|
155
|
+
camera.storageSettings.values.ipAddress = ipAddress;
|
|
156
|
+
camera.storageSettings.values.variantType = variantType;
|
|
157
|
+
camera.storageSettings.values.rtspChannel = channel;
|
|
158
|
+
camera.storageSettings.values.capabilities = deviceCapabilities;
|
|
159
|
+
camera.storageSettings.values.uid = uid;
|
|
160
|
+
}
|
|
161
|
+
} catch (e) {
|
|
162
|
+
logger.error("Failed to report devices", e?.message || String(e));
|
|
163
|
+
throw e;
|
|
60
164
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
onNvr: !!this.nvrDevice
|
|
76
|
-
});
|
|
77
|
-
logger.log(`Discovering ${multifocalInfo.channels.length} lenses`);
|
|
78
|
-
logger.debug({ multifocalInfo, capabilities });
|
|
79
|
-
|
|
80
|
-
this.storageSettings.values.multifocalInfo = multifocalInfo;
|
|
81
|
-
|
|
82
|
-
for (const channelInfo of multifocalInfo?.channels ?? []) {
|
|
83
|
-
const { channel, lensType, variantType } = channelInfo;
|
|
84
|
-
|
|
85
|
-
const name = `${this.name} - ${lensType}`;
|
|
86
|
-
const nativeId = `${this.nativeId}-${lensType}${this.isBattery ? batteryCameraSuffix : cameraSuffix}`;
|
|
87
|
-
|
|
88
|
-
this.channelToNativeIdMap.set(channel, nativeId);
|
|
89
|
-
const { interfaces, capabilities: deviceCapabilities } = await this.getInterfaces();
|
|
90
|
-
|
|
91
|
-
const device: Device = {
|
|
92
|
-
providerNativeId: this.nativeId,
|
|
93
|
-
name,
|
|
94
|
-
nativeId,
|
|
95
|
-
info: {
|
|
96
|
-
...this.info,
|
|
97
|
-
metadata: {
|
|
98
|
-
channel,
|
|
99
|
-
lensType
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
interfaces,
|
|
103
|
-
type: ScryptedDeviceType.Camera,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
await sdk.deviceManager.onDeviceDiscovered(device);
|
|
107
|
-
|
|
108
|
-
logger.log(`Discovering lens ${lensType}`);
|
|
109
|
-
logger.debug(`${JSON.stringify({ interfaces, deviceCapabilities })}`)
|
|
110
|
-
|
|
111
|
-
const camera = await this.getDevice(nativeId);
|
|
112
|
-
|
|
113
|
-
if (!camera) {
|
|
114
|
-
logger.error(`Failed to get device ${nativeId}`);
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
camera.storageSettings.values.rtspChannel = channel;
|
|
119
|
-
camera.classes = objects;
|
|
120
|
-
camera.presets = presets;
|
|
121
|
-
camera.storageSettings.values.username = username;
|
|
122
|
-
camera.storageSettings.values.password = password;
|
|
123
|
-
camera.storageSettings.values.ipAddress = ipAddress;
|
|
124
|
-
camera.storageSettings.values.variantType = variantType;
|
|
125
|
-
camera.storageSettings.values.rtspChannel = channel;
|
|
126
|
-
camera.storageSettings.values.capabilities = deviceCapabilities;
|
|
127
|
-
camera.storageSettings.values.uid = uid;
|
|
128
|
-
}
|
|
129
|
-
} catch (e) {
|
|
130
|
-
logger.error('Failed to report devices', e?.message || String(e));
|
|
131
|
-
throw e;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async getDevice(nativeId: string) {
|
|
136
|
-
if (nativeId.endsWith(cameraSuffix) || nativeId.endsWith(batteryCameraSuffix)) {
|
|
137
|
-
let device = this.lensDevicesMap.get(nativeId);
|
|
138
|
-
if (!device) {
|
|
139
|
-
if (nativeId.endsWith(batteryCameraSuffix)) {
|
|
140
|
-
device = new ReolinkCamera(nativeId, this.plugin, { type: 'battery', multiFocalDevice: this });
|
|
141
|
-
} else {
|
|
142
|
-
device = new ReolinkCamera(nativeId, this.plugin, { type: 'regular', multiFocalDevice: this });
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (device) {
|
|
147
|
-
this.lensDevicesMap.set(nativeId, device);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return device;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async getDevice(nativeId: string) {
|
|
168
|
+
if (
|
|
169
|
+
nativeId.endsWith(cameraSuffix) ||
|
|
170
|
+
nativeId.endsWith(batteryCameraSuffix)
|
|
171
|
+
) {
|
|
172
|
+
let device = this.lensDevicesMap.get(nativeId);
|
|
173
|
+
if (!device) {
|
|
174
|
+
if (nativeId.endsWith(batteryCameraSuffix)) {
|
|
175
|
+
device = new ReolinkCamera(nativeId, this.plugin, {
|
|
176
|
+
type: "battery",
|
|
177
|
+
multiFocalDevice: this,
|
|
178
|
+
});
|
|
151
179
|
} else {
|
|
152
|
-
|
|
180
|
+
device = new ReolinkCamera(nativeId, this.plugin, {
|
|
181
|
+
type: "regular",
|
|
182
|
+
multiFocalDevice: this,
|
|
183
|
+
});
|
|
153
184
|
}
|
|
154
|
-
|
|
185
|
+
}
|
|
155
186
|
|
|
156
|
-
|
|
157
|
-
this.lensDevicesMap.
|
|
158
|
-
|
|
159
|
-
}
|
|
187
|
+
if (device) {
|
|
188
|
+
this.lensDevicesMap.set(nativeId, device);
|
|
189
|
+
}
|
|
160
190
|
|
|
161
|
-
|
|
162
|
-
|
|
191
|
+
return device;
|
|
192
|
+
} else {
|
|
193
|
+
return super.getDevice(nativeId);
|
|
163
194
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async releaseDevice(id: string, nativeId: string) {
|
|
198
|
+
this.lensDevicesMap.delete(nativeId);
|
|
199
|
+
super.releaseDevice(id, nativeId);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async unsubscribeFromAllEvents(): Promise<void> {
|
|
203
|
+
await super.unsubscribeFromEvents();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public async runDiagnostics(): Promise<void> {
|
|
207
|
+
const logger = this.getBaichuanLogger();
|
|
208
|
+
logger.log(`Starting Multifocal diagnostics...`);
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const { ipAddress, username, password } = this.storageSettings.values;
|
|
212
|
+
if (!ipAddress || !username || !password) {
|
|
213
|
+
throw new Error("Missing device credentials");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const outputPath =
|
|
217
|
+
this.storageSettings.values.diagnosticsOutputPath ||
|
|
218
|
+
process.env.SCRYPTED_PLUGIN_VOLUME ||
|
|
219
|
+
"";
|
|
220
|
+
if (!outputPath) {
|
|
221
|
+
throw new Error("Diagnostics output path is required");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const api = await this.ensureClient();
|
|
225
|
+
|
|
226
|
+
const channel = this.storageSettings.values.rtspChannel || 0;
|
|
227
|
+
const durationSeconds = 8;
|
|
228
|
+
const result = await api.runMultifocalDiagnosticsConsecutively({
|
|
229
|
+
logger,
|
|
230
|
+
outDir: outputPath,
|
|
231
|
+
channel,
|
|
232
|
+
durationSeconds,
|
|
233
|
+
rtmpApps: ["bcs"],
|
|
234
|
+
probeFull: true,
|
|
235
|
+
onNvr: !!this.nvrDevice,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
logger.log(
|
|
239
|
+
`Multifocal diagnostics completed successfully. Output directory: ${result.runDir}`,
|
|
240
|
+
);
|
|
241
|
+
logger.log(`Results file: ${result.resultsPath}`);
|
|
242
|
+
logger.log(`Streams directory: ${result.streamsDir}`);
|
|
243
|
+
} catch (e) {
|
|
244
|
+
logger.error("Failed to run NVR diagnostics", e?.message || String(e));
|
|
245
|
+
throw e;
|
|
201
246
|
}
|
|
247
|
+
}
|
|
202
248
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Use base class implementation
|
|
209
|
-
return await this.ensureBaichuanClient();
|
|
249
|
+
async ensureClient(): Promise<ReolinkBaichuanApi> {
|
|
250
|
+
if (this.nvrDevice) {
|
|
251
|
+
return await this.nvrDevice.ensureBaichuanClient();
|
|
210
252
|
}
|
|
211
253
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
username,
|
|
225
|
-
password,
|
|
226
|
-
uid: normalizedUid,
|
|
227
|
-
transport: this.transport,
|
|
228
|
-
debugOptions,
|
|
229
|
-
udpDiscoveryMethod: discoveryMethod,
|
|
230
|
-
};
|
|
254
|
+
// Use base class implementation
|
|
255
|
+
return await this.ensureBaichuanClient();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Create a dedicated Baichuan API session for streaming (used by StreamManager).
|
|
260
|
+
* MultiFocal creates its own socket for stream clients, or delegates to NVR if on NVR.
|
|
261
|
+
*/
|
|
262
|
+
async createStreamClient(streamKey: string): Promise<ReolinkBaichuanApi> {
|
|
263
|
+
// If on NVR, delegate to NVR to create the socket
|
|
264
|
+
if (this.nvrDevice) {
|
|
265
|
+
return await this.nvrDevice.createStreamClient(streamKey);
|
|
231
266
|
}
|
|
232
267
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (this.nvrDevice) {
|
|
240
|
-
return await this.nvrDevice.createStreamClient(streamKey);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// For multifocal battery cams (BCUDP), reuse the main client to avoid D2C_DISC storms.
|
|
244
|
-
if (this.isBattery) {
|
|
245
|
-
// For battery (BCUDP) cameras, streaming must be keyed by streamKey.
|
|
246
|
-
// Do NOT reuse ensureClient(): composite needs two concurrent streams, and single-lens streams
|
|
247
|
-
// should reuse the same API that composite already created for that same streamKey.
|
|
248
|
-
return await super.createStreamClient(streamKey);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Otherwise, use base class createStreamClient which manages stream clients per streamKey
|
|
252
|
-
return await super.createStreamClient(streamKey);
|
|
268
|
+
// For multifocal battery cams (BCUDP), reuse the main client to avoid D2C_DISC storms.
|
|
269
|
+
if (this.isBattery) {
|
|
270
|
+
// For battery (BCUDP) cameras, streaming must be keyed by streamKey.
|
|
271
|
+
// Do NOT reuse ensureClient(): composite needs two concurrent streams, and single-lens streams
|
|
272
|
+
// should reuse the same API that composite already created for that same streamKey.
|
|
273
|
+
return await super.createStreamClient(streamKey);
|
|
253
274
|
}
|
|
254
275
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
// logger.debug(`Found ${devices.length} lens devices: ${devices.map(d => d.nativeId).join(', ')}`);
|
|
276
|
+
// Otherwise, use base class createStreamClient which manages stream clients per streamKey
|
|
277
|
+
return await super.createStreamClient(streamKey);
|
|
278
|
+
}
|
|
259
279
|
|
|
260
|
-
|
|
261
|
-
|
|
280
|
+
getLensDevices() {
|
|
281
|
+
const devices = Array.from(this.lensDevicesMap.values());
|
|
282
|
+
// const logger = this.getBaichuanLogger();
|
|
283
|
+
// logger.debug(`Found ${devices.length} lens devices: ${devices.map(d => d.nativeId).join(', ')}`);
|
|
262
284
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const lensDevices = this.getLensDevices();
|
|
285
|
+
return devices;
|
|
286
|
+
}
|
|
266
287
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
288
|
+
async updateBatteryInfo() {
|
|
289
|
+
const batteryInfo = await super.updateBatteryInfo();
|
|
290
|
+
const lensDevices = this.getLensDevices();
|
|
270
291
|
|
|
271
|
-
|
|
292
|
+
for (const camera of lensDevices) {
|
|
293
|
+
await camera.updateBatteryInfo(batteryInfo);
|
|
272
294
|
}
|
|
273
295
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const logger = this.getBaichuanLogger();
|
|
277
|
-
const lensDevices = this.getLensDevices();
|
|
296
|
+
return batteryInfo;
|
|
297
|
+
}
|
|
278
298
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async updateSleepingState(sleepStatus: SleepStatus) {
|
|
286
|
-
const logger = this.getBaichuanLogger();
|
|
287
|
-
await super.updateSleepingState(sleepStatus);
|
|
288
|
-
const lensDevices = this.getLensDevices();
|
|
299
|
+
onSimpleEvent(ev: ReolinkSimpleEvent) {
|
|
300
|
+
super.onSimpleEvent(ev);
|
|
301
|
+
const logger = this.getBaichuanLogger();
|
|
302
|
+
const lensDevices = this.getLensDevices();
|
|
289
303
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
304
|
+
for (const camera of lensDevices) {
|
|
305
|
+
logger.debug(
|
|
306
|
+
`Forward ${ev.type} event to lens device ${camera.nativeId}`,
|
|
307
|
+
);
|
|
308
|
+
camera.onSimpleEvent(ev);
|
|
294
309
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async updateSleepingState(sleepStatus: SleepStatus) {
|
|
313
|
+
const logger = this.getBaichuanLogger();
|
|
314
|
+
await super.updateSleepingState(sleepStatus);
|
|
315
|
+
const lensDevices = this.getLensDevices();
|
|
316
|
+
|
|
317
|
+
for (const camera of lensDevices) {
|
|
318
|
+
logger.debug(
|
|
319
|
+
`Forward ${JSON.stringify(sleepStatus)} sleeping state to lens device ${camera.nativeId}`,
|
|
320
|
+
);
|
|
321
|
+
await camera.updateSleepingState(sleepStatus);
|
|
305
322
|
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async updateOnlineState(isOnline: boolean) {
|
|
326
|
+
const logger = this.getBaichuanLogger();
|
|
327
|
+
await super.updateOnlineState(isOnline);
|
|
328
|
+
const lensDevices = this.getLensDevices();
|
|
329
|
+
|
|
330
|
+
for (const camera of lensDevices) {
|
|
331
|
+
logger.debug(
|
|
332
|
+
`Forward ${isOnline ? "online" : "offline"} state to lens device ${camera.nativeId}`,
|
|
333
|
+
);
|
|
334
|
+
await camera.updateOnlineState(isOnline);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
306
337
|
}
|
|
307
|
-
|