@apocaliss92/scrypted-reolink-native 0.1.9 → 0.1.11
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 +478 -0
- package/src/camera-battery.ts +40 -36
- package/src/camera.ts +6 -9
- package/src/common.ts +108 -231
- package/src/connect.ts +1 -2
- package/src/debug-options.ts +1 -1
- package/src/intercom.ts +3 -3
- package/src/nvr.ts +66 -217
- package/src/stream-utils.ts +19 -8
package/src/camera-battery.ts
CHANGED
|
@@ -36,16 +36,19 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async takePicture(options?: RequestPictureOptions): Promise<MediaObject> {
|
|
39
|
+
const logger = this.getBaichuanLogger();
|
|
39
40
|
// Allow new snapshot if:
|
|
40
41
|
// 1. forceNewSnapshot is true, OR
|
|
41
42
|
// 2. Camera is awake AND last snapshot was taken at least 10 seconds ago
|
|
42
|
-
const minSnapshotIntervalMs = 10_000; // 10 seconds
|
|
43
|
-
const now = Date.now();
|
|
44
|
-
const shouldTakeNewSnapshot = this.forceNewSnapshot
|
|
45
|
-
|
|
43
|
+
// const minSnapshotIntervalMs = 10_000; // 10 seconds
|
|
44
|
+
// const now = Date.now();
|
|
45
|
+
const shouldTakeNewSnapshot = this.forceNewSnapshot;
|
|
46
|
+
// const now = Date.now();
|
|
47
|
+
// const shouldTakeNewSnapshot = this.forceNewSnapshot ||
|
|
48
|
+
// (!this.sleeping && this.lastPicture && (now - this.lastPicture.atMs >= minSnapshotIntervalMs));
|
|
46
49
|
|
|
47
50
|
if (!shouldTakeNewSnapshot && this.lastPicture) {
|
|
48
|
-
|
|
51
|
+
logger.debug(`Returning cached snapshot, taken at ${new Date(this.lastPicture.atMs).toLocaleString()}`);
|
|
49
52
|
return this.lastPicture.mo;
|
|
50
53
|
}
|
|
51
54
|
|
|
@@ -53,7 +56,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
53
56
|
return await this.takePictureInFlight;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
logger.log(`Taking new snapshot from camera (forceNewSnapshot: ${this.forceNewSnapshot})`);
|
|
57
60
|
this.forceNewSnapshot = false;
|
|
58
61
|
|
|
59
62
|
this.takePictureInFlight = (async () => {
|
|
@@ -63,7 +66,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
63
66
|
});
|
|
64
67
|
const mo = await sdk.mediaManager.createMediaObject(snapshotBuffer, 'image/jpeg');
|
|
65
68
|
this.lastPicture = { mo, atMs: Date.now() };
|
|
66
|
-
|
|
69
|
+
logger.log(`Snapshot taken at ${new Date(this.lastPicture.atMs).toLocaleString()}`);
|
|
67
70
|
return mo;
|
|
68
71
|
})();
|
|
69
72
|
|
|
@@ -104,9 +107,10 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
104
107
|
|
|
105
108
|
private startPeriodicTasks(): void {
|
|
106
109
|
if (this.periodicStarted) return;
|
|
110
|
+
const logger = this.getBaichuanLogger();
|
|
107
111
|
this.periodicStarted = true;
|
|
108
112
|
|
|
109
|
-
|
|
113
|
+
logger.log('Starting periodic tasks for battery camera');
|
|
110
114
|
|
|
111
115
|
// Check sleeping state every 5 seconds (non-blocking)
|
|
112
116
|
if (!this.nvrDevice) {
|
|
@@ -117,7 +121,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
117
121
|
|
|
118
122
|
if (!api) {
|
|
119
123
|
if (!this.sleeping) {
|
|
120
|
-
|
|
124
|
+
logger.log('Camera is sleeping: no active Baichuan client');
|
|
121
125
|
this.sleeping = true;
|
|
122
126
|
}
|
|
123
127
|
return;
|
|
@@ -126,7 +130,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
126
130
|
const sleepStatus = api.getSleepStatus({ channel });
|
|
127
131
|
await this.updateSleepingState(sleepStatus);
|
|
128
132
|
} catch (e) {
|
|
129
|
-
|
|
133
|
+
logger.warn('Error checking sleeping state:', e);
|
|
130
134
|
}
|
|
131
135
|
}, 5_000);
|
|
132
136
|
}
|
|
@@ -138,25 +142,25 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
138
142
|
this.updateBatteryAndSnapshot().catch(() => { });
|
|
139
143
|
}, updateIntervalMs);
|
|
140
144
|
|
|
141
|
-
|
|
145
|
+
logger.log(`Periodic tasks started: sleep check every 5s, battery update every ${batteryUpdateIntervalMinutes} minutes`);
|
|
142
146
|
}
|
|
143
147
|
|
|
144
148
|
async updateSleepingState(sleepStatus: SleepStatus): Promise<void> {
|
|
145
149
|
try {
|
|
146
150
|
if (this.isBatteryInfoLoggingEnabled()) {
|
|
147
|
-
this.
|
|
151
|
+
this.getBaichuanLogger().debug('getSleepStatus result:', JSON.stringify(sleepStatus));
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
if (sleepStatus.state === 'sleeping') {
|
|
151
155
|
if (!this.sleeping) {
|
|
152
|
-
this.
|
|
156
|
+
this.getBaichuanLogger().log(`Camera is sleeping: ${sleepStatus.reason}`);
|
|
153
157
|
this.sleeping = true;
|
|
154
158
|
}
|
|
155
159
|
} else if (sleepStatus.state === 'awake') {
|
|
156
160
|
// Camera is awake
|
|
157
161
|
const wasSleeping = this.sleeping;
|
|
158
162
|
if (wasSleeping) {
|
|
159
|
-
this.
|
|
163
|
+
this.getBaichuanLogger().log(`Camera woke up: ${sleepStatus.reason}`);
|
|
160
164
|
this.sleeping = false;
|
|
161
165
|
}
|
|
162
166
|
|
|
@@ -168,11 +172,11 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
168
172
|
}
|
|
169
173
|
} else {
|
|
170
174
|
// Unknown state
|
|
171
|
-
this.
|
|
175
|
+
this.getBaichuanLogger().debug(`Sleep status unknown: ${sleepStatus.reason}`);
|
|
172
176
|
}
|
|
173
177
|
} catch (e) {
|
|
174
178
|
// Silently ignore errors in sleep check to avoid spam
|
|
175
|
-
this.
|
|
179
|
+
this.getBaichuanLogger().debug('Error in checkSleepingState:', e);
|
|
176
180
|
}
|
|
177
181
|
}
|
|
178
182
|
|
|
@@ -182,7 +186,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
182
186
|
|
|
183
187
|
const batteryInfo = await api.getBatteryInfo(channel);
|
|
184
188
|
if (this.isBatteryInfoLoggingEnabled()) {
|
|
185
|
-
this.
|
|
189
|
+
this.getBaichuanLogger().debug('getBatteryInfo result:', JSON.stringify(batteryInfo));
|
|
186
190
|
}
|
|
187
191
|
|
|
188
192
|
if (batteryInfo.batteryPercent !== undefined) {
|
|
@@ -195,17 +199,17 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
195
199
|
if (batteryInfo.chargeStatus !== undefined) {
|
|
196
200
|
// chargeStatus: "0"=charging, "1"=discharging, "2"=full
|
|
197
201
|
const charging = batteryInfo.chargeStatus === "0" || batteryInfo.chargeStatus === "2";
|
|
198
|
-
this.
|
|
202
|
+
this.getBaichuanLogger().log(`Battery level changed: ${oldLevel}% → ${batteryInfo.batteryPercent}% (charging: ${charging})`);
|
|
199
203
|
} else {
|
|
200
|
-
this.
|
|
204
|
+
this.getBaichuanLogger().log(`Battery level changed: ${oldLevel}% → ${batteryInfo.batteryPercent}%`);
|
|
201
205
|
}
|
|
202
206
|
} else if (oldLevel === undefined) {
|
|
203
207
|
// First time setting battery level
|
|
204
208
|
if (batteryInfo.chargeStatus !== undefined) {
|
|
205
209
|
const charging = batteryInfo.chargeStatus === "0" || batteryInfo.chargeStatus === "2";
|
|
206
|
-
this.
|
|
210
|
+
this.getBaichuanLogger().log(`Battery level set: ${batteryInfo.batteryPercent}% (charging: ${charging})`);
|
|
207
211
|
} else {
|
|
208
|
-
this.
|
|
212
|
+
this.getBaichuanLogger().log(`Battery level set: ${batteryInfo.batteryPercent}%`);
|
|
209
213
|
}
|
|
210
214
|
}
|
|
211
215
|
}
|
|
@@ -214,7 +218,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
214
218
|
private async updateBatteryAndSnapshot(): Promise<void> {
|
|
215
219
|
// Prevent multiple simultaneous calls
|
|
216
220
|
if (this.batteryUpdateInProgress) {
|
|
217
|
-
this.
|
|
221
|
+
this.getBaichuanLogger().debug('Battery update already in progress, skipping');
|
|
218
222
|
return;
|
|
219
223
|
}
|
|
220
224
|
|
|
@@ -222,12 +226,12 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
222
226
|
try {
|
|
223
227
|
const channel = this.storageSettings.values.rtspChannel;
|
|
224
228
|
const updateIntervalMinutes = this.storageSettings.values.batteryUpdateIntervalMinutes ?? 10;
|
|
225
|
-
this.
|
|
229
|
+
this.getBaichuanLogger().log(`Force battery update interval started (every ${updateIntervalMinutes} minutes)`);
|
|
226
230
|
|
|
227
231
|
// Ensure we have a client connection
|
|
228
232
|
const api = await this.ensureClient();
|
|
229
233
|
if (!api) {
|
|
230
|
-
this.
|
|
234
|
+
this.getBaichuanLogger().warn('Failed to ensure client connection for battery update');
|
|
231
235
|
return;
|
|
232
236
|
}
|
|
233
237
|
|
|
@@ -236,12 +240,12 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
236
240
|
|
|
237
241
|
// If camera is sleeping, wake it up
|
|
238
242
|
if (sleepStatus.state === 'sleeping') {
|
|
239
|
-
this.
|
|
243
|
+
this.getBaichuanLogger().log('Camera is sleeping, waking up for periodic update...');
|
|
240
244
|
try {
|
|
241
245
|
await api.wakeUp(channel, { waitAfterWakeMs: 2000 });
|
|
242
|
-
this.
|
|
246
|
+
this.getBaichuanLogger().log('Wake command sent, waiting for camera to wake up...');
|
|
243
247
|
} catch (wakeError) {
|
|
244
|
-
this.
|
|
248
|
+
this.getBaichuanLogger().warn('Failed to wake up camera:', wakeError);
|
|
245
249
|
return;
|
|
246
250
|
}
|
|
247
251
|
|
|
@@ -255,14 +259,14 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
255
259
|
sleepStatus = api.getSleepStatus({ channel });
|
|
256
260
|
if (sleepStatus.state === 'awake') {
|
|
257
261
|
awake = true;
|
|
258
|
-
this.
|
|
262
|
+
this.getBaichuanLogger().log('Camera is now awake');
|
|
259
263
|
this.sleeping = false;
|
|
260
264
|
break;
|
|
261
265
|
}
|
|
262
266
|
}
|
|
263
267
|
|
|
264
268
|
if (!awake) {
|
|
265
|
-
this.
|
|
269
|
+
this.getBaichuanLogger().warn('Camera did not wake up within timeout, skipping update');
|
|
266
270
|
return;
|
|
267
271
|
}
|
|
268
272
|
} else if (sleepStatus.state === 'awake') {
|
|
@@ -274,26 +278,26 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
274
278
|
try {
|
|
275
279
|
await this.updateBatteryInfo();
|
|
276
280
|
} catch (e) {
|
|
277
|
-
this.
|
|
281
|
+
this.getBaichuanLogger().warn('Failed to get battery info during periodic update:', e);
|
|
278
282
|
}
|
|
279
283
|
|
|
280
284
|
// 2. Align auxiliary devices state
|
|
281
285
|
try {
|
|
282
286
|
await this.alignAuxDevicesState();
|
|
283
287
|
} catch (e) {
|
|
284
|
-
this.
|
|
288
|
+
this.getBaichuanLogger().warn('Failed to align auxiliary devices state:', e);
|
|
285
289
|
}
|
|
286
290
|
|
|
287
291
|
// 3. Update snapshot
|
|
288
292
|
try {
|
|
289
293
|
this.forceNewSnapshot = true;
|
|
290
294
|
await this.takePicture();
|
|
291
|
-
this.
|
|
295
|
+
this.getBaichuanLogger().log('Snapshot updated during periodic update');
|
|
292
296
|
} catch (snapshotError) {
|
|
293
|
-
this.
|
|
297
|
+
this.getBaichuanLogger().warn('Failed to update snapshot during periodic update:', snapshotError);
|
|
294
298
|
}
|
|
295
299
|
} catch (e) {
|
|
296
|
-
this.
|
|
300
|
+
this.getBaichuanLogger().warn('Failed to update battery and snapshot', e);
|
|
297
301
|
} finally {
|
|
298
302
|
this.batteryUpdateInProgress = false;
|
|
299
303
|
}
|
|
@@ -313,7 +317,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
313
317
|
await this.baichuanApi?.close();
|
|
314
318
|
}
|
|
315
319
|
catch (e) {
|
|
316
|
-
this.
|
|
320
|
+
this.getBaichuanLogger().warn('Error closing Baichuan client during reset', e);
|
|
317
321
|
}
|
|
318
322
|
finally {
|
|
319
323
|
this.baichuanApi = undefined;
|
|
@@ -331,7 +335,7 @@ export class ReolinkNativeBatteryCamera extends CommonCameraMixin {
|
|
|
331
335
|
|
|
332
336
|
if (reason) {
|
|
333
337
|
const message = reason?.message || reason?.toString?.() || reason;
|
|
334
|
-
this.
|
|
338
|
+
this.getBaichuanLogger().warn(`Baichuan client reset requested: ${message}`);
|
|
335
339
|
}
|
|
336
340
|
}
|
|
337
341
|
|
package/src/camera.ts
CHANGED
|
@@ -45,7 +45,7 @@ export class ReolinkNativeCamera extends CommonCameraMixin {
|
|
|
45
45
|
await this.baichuanApi?.close();
|
|
46
46
|
}
|
|
47
47
|
catch (e) {
|
|
48
|
-
this.
|
|
48
|
+
this.getBaichuanLogger().warn('Error closing Baichuan client during reset', e);
|
|
49
49
|
}
|
|
50
50
|
finally {
|
|
51
51
|
this.baichuanApi = undefined;
|
|
@@ -59,7 +59,7 @@ export class ReolinkNativeCamera extends CommonCameraMixin {
|
|
|
59
59
|
|
|
60
60
|
if (reason) {
|
|
61
61
|
const message = reason?.message || reason?.toString?.() || reason;
|
|
62
|
-
this.
|
|
62
|
+
this.getBaichuanLogger().warn(`Baichuan client reset requested: ${message}`);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -90,9 +90,6 @@ export class ReolinkNativeCamera extends CommonCameraMixin {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
public getLogger() {
|
|
94
|
-
return this.console;
|
|
95
|
-
}
|
|
96
93
|
|
|
97
94
|
async init() {
|
|
98
95
|
this.startPeriodicTasks();
|
|
@@ -141,13 +138,13 @@ export class ReolinkNativeCamera extends CommonCameraMixin {
|
|
|
141
138
|
if (this.periodicStarted) return;
|
|
142
139
|
this.periodicStarted = true;
|
|
143
140
|
|
|
144
|
-
this.
|
|
141
|
+
this.getBaichuanLogger().log('Starting periodic tasks for regular camera');
|
|
145
142
|
|
|
146
143
|
this.statusPollTimer = setInterval(() => {
|
|
147
144
|
this.periodic10sTick().catch(() => { });
|
|
148
145
|
}, 10_000);
|
|
149
146
|
|
|
150
|
-
this.
|
|
147
|
+
this.getBaichuanLogger().log('Periodic tasks started: status poll every 10s');
|
|
151
148
|
}
|
|
152
149
|
|
|
153
150
|
private async periodic10sTick(): Promise<void> {
|
|
@@ -160,7 +157,7 @@ export class ReolinkNativeCamera extends CommonCameraMixin {
|
|
|
160
157
|
}
|
|
161
158
|
|
|
162
159
|
async processEvents(events: { motion?: boolean; objects?: string[] }) {
|
|
163
|
-
const logger = this.
|
|
160
|
+
const logger = this.getBaichuanLogger();
|
|
164
161
|
|
|
165
162
|
if (!this.isEventDispatchEnabled()) return;
|
|
166
163
|
|
|
@@ -215,7 +212,7 @@ export class ReolinkNativeCamera extends CommonCameraMixin {
|
|
|
215
212
|
return mo;
|
|
216
213
|
});
|
|
217
214
|
} catch (e) {
|
|
218
|
-
this.
|
|
215
|
+
this.getBaichuanLogger().error('Error taking snapshot', e);
|
|
219
216
|
throw e;
|
|
220
217
|
}
|
|
221
218
|
}
|