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