@apocaliss92/scrypted-reolink-native 0.5.22 → 0.5.23
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 +2 -2
- package/src/baichuan-base.ts +14 -0
- package/src/camera.ts +46 -0
- package/src/email-push-server-device.ts +10 -2
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apocaliss92/scrypted-reolink-native",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.23",
|
|
4
4
|
"description": "Use any reolink camera with Scrypted, even older/unsupported models without HTTP protocol support",
|
|
5
5
|
"author": "@apocaliss92",
|
|
6
6
|
"license": "Apache",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
]
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@apocaliss92/nodelink-js": "^0.4.
|
|
47
|
+
"@apocaliss92/nodelink-js": "^0.4.30",
|
|
48
48
|
"@scrypted/common": "file:../../scrypted/common",
|
|
49
49
|
"@scrypted/rtsp": "file:../../scrypted/plugins/rtsp",
|
|
50
50
|
"@scrypted/sdk": "^0.3.118"
|
package/src/baichuan-base.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
BaichuanClientOptions,
|
|
3
|
+
EmailPushEvent,
|
|
3
4
|
ReolinkBaichuanApi,
|
|
4
5
|
ReolinkSimpleEvent,
|
|
5
6
|
} from "@apocaliss92/nodelink-js" with { "resolution-mode": "import" };
|
|
@@ -32,6 +33,16 @@ export interface BaichuanConnectionCallbacks {
|
|
|
32
33
|
* leave undefined on NVR children where email-push isn't meaningful.
|
|
33
34
|
*/
|
|
34
35
|
emailPushCameraId?: () => string;
|
|
36
|
+
/**
|
|
37
|
+
* Optional. When the email-push event carries an image attachment
|
|
38
|
+
* (typical for `attachmentType=picture` on motion), the camera
|
|
39
|
+
* receives the full event so it can republish the snapshot —
|
|
40
|
+
* usually by updating its `lastPicture` cache so subsequent
|
|
41
|
+
* `takePicture()` calls return the fresh thumbnail without waking
|
|
42
|
+
* the camera. Invoked AFTER the simple-event dispatch so any motion
|
|
43
|
+
* listener has already fired.
|
|
44
|
+
*/
|
|
45
|
+
onEmailPushEvent?: (event: EmailPushEvent) => void;
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
/**
|
|
@@ -908,6 +919,9 @@ export abstract class BaseBaichuanClass extends ScryptedDeviceBase {
|
|
|
908
919
|
this.currentEmailPushOff = api.subscribeEmailPushEvents({
|
|
909
920
|
cameraId: callbacks.emailPushCameraId(),
|
|
910
921
|
channel: 0,
|
|
922
|
+
...(callbacks.onEmailPushEvent
|
|
923
|
+
? { onEvent: callbacks.onEmailPushEvent }
|
|
924
|
+
: {}),
|
|
911
925
|
});
|
|
912
926
|
logger.debug("Bridged email-push bus to onSimpleEvent");
|
|
913
927
|
} catch (e) {
|
package/src/camera.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
BatteryInfo,
|
|
3
3
|
DeviceCapabilities,
|
|
4
|
+
EmailPushEvent,
|
|
4
5
|
NativeVideoStreamVariant,
|
|
5
6
|
PtzCommand,
|
|
6
7
|
PtzPreset,
|
|
@@ -1614,6 +1615,14 @@ export class ReolinkCamera
|
|
|
1614
1615
|
// (singleton under the provider) maps `cam-<nativeId>@<domain>`
|
|
1615
1616
|
// RCPT addresses back to this `nativeId`.
|
|
1616
1617
|
emailPushCameraId: () => this.nativeId ?? "",
|
|
1618
|
+
// When the e-mail carries the snapshot Reolink sends with
|
|
1619
|
+
// `attachmentType=picture`, hand it to the camera's `lastPicture`
|
|
1620
|
+
// cache. Downstream consumers (Snapshot mixin → MQTT image
|
|
1621
|
+
// entity, Advanced Notifier, HA discovery) call `takePicture()`
|
|
1622
|
+
// on the back of the motion event; for battery cams that returns
|
|
1623
|
+
// the cached value, so dropping the fresh snapshot in here makes
|
|
1624
|
+
// the trigger frame surface in MQTT/HA without waking the camera.
|
|
1625
|
+
onEmailPushEvent: (event) => this.handleEmailPushSnapshot(event),
|
|
1617
1626
|
};
|
|
1618
1627
|
}
|
|
1619
1628
|
|
|
@@ -2734,6 +2743,43 @@ export class ReolinkCamera
|
|
|
2734
2743
|
}
|
|
2735
2744
|
}
|
|
2736
2745
|
|
|
2746
|
+
/**
|
|
2747
|
+
* Called from `baichuan-base.subscribeToEvents` when a per-camera
|
|
2748
|
+
* email-push event lands on the bus. If the camera attached the
|
|
2749
|
+
* trigger-frame JPEG (the common case for `attachmentType=picture`),
|
|
2750
|
+
* we wrap it in a Scrypted MediaObject and overwrite `lastPicture`
|
|
2751
|
+
* so the next `takePicture()` returns the fresh snapshot — which is
|
|
2752
|
+
* what the Snapshot mixin → MQTT/HA image entity republishes off the
|
|
2753
|
+
* back of the motion event. Without this hook, battery cams have
|
|
2754
|
+
* nothing fresh to give and HA shows the previous cached frame.
|
|
2755
|
+
*/
|
|
2756
|
+
private async handleEmailPushSnapshot(
|
|
2757
|
+
event: EmailPushEvent,
|
|
2758
|
+
): Promise<void> {
|
|
2759
|
+
const logger = this.getBaichuanLogger();
|
|
2760
|
+
if (!event.attachment) {
|
|
2761
|
+
logger.debug(
|
|
2762
|
+
`E-mail Push event without attachment (type=${event.inferredType}); skipping snapshot cache update`,
|
|
2763
|
+
);
|
|
2764
|
+
return;
|
|
2765
|
+
}
|
|
2766
|
+
try {
|
|
2767
|
+
const mo = await this.createMediaObject(
|
|
2768
|
+
event.attachment.data,
|
|
2769
|
+
event.attachment.contentType,
|
|
2770
|
+
);
|
|
2771
|
+
this.lastPicture = { mo, atMs: event.receivedAtMs };
|
|
2772
|
+
this.forceNewSnapshot = false;
|
|
2773
|
+
logger.log(
|
|
2774
|
+
`E-mail Push snapshot cached (${event.attachment.data.length}B, ${event.attachment.contentType}) — next takePicture will serve it`,
|
|
2775
|
+
);
|
|
2776
|
+
} catch (e) {
|
|
2777
|
+
logger.warn(
|
|
2778
|
+
`E-mail Push: failed to wrap attachment as MediaObject: ${e?.message || String(e)}`,
|
|
2779
|
+
);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2737
2783
|
async takePictureInternal(client: ReolinkBaichuanApi) {
|
|
2738
2784
|
const { rtspChannel, variantType } = this.storageSettings.values;
|
|
2739
2785
|
const logger = this.getBaichuanLogger();
|
|
@@ -214,7 +214,13 @@ export class EmailPushServerDevice
|
|
|
214
214
|
managerHost,
|
|
215
215
|
managerPort: cfg.port,
|
|
216
216
|
domain: cfg.domain,
|
|
217
|
-
|
|
217
|
+
// The lib's `resolveCameraIdFromRecipient` matches `^cam-(.+)$`
|
|
218
|
+
// and feeds the captured group to `cameraResolver`. We MUST send
|
|
219
|
+
// the recipient with the `cam-` prefix so the camera-side
|
|
220
|
+
// MAIL FROM produces `cam-<nativeId>@<domain>`; without it every
|
|
221
|
+
// delivery is rejected with `550 Unknown recipient` and motion
|
|
222
|
+
// events never reach Scrypted.
|
|
223
|
+
recipientLocalPart: `cam-${nativeId}`,
|
|
218
224
|
sendNickname: cam.name ?? nativeId,
|
|
219
225
|
...(cfg.requireAuth
|
|
220
226
|
? {
|
|
@@ -536,7 +542,9 @@ export class EmailPushServerDevice
|
|
|
536
542
|
managerHost,
|
|
537
543
|
managerPort: cfg.port,
|
|
538
544
|
domain: cfg.domain,
|
|
539
|
-
|
|
545
|
+
// See `getManagerSetupParamsForCamera` for why the `cam-`
|
|
546
|
+
// prefix is mandatory.
|
|
547
|
+
recipientLocalPart: `cam-${nativeId}`,
|
|
540
548
|
sendNickname: cam.name ?? nativeId,
|
|
541
549
|
attachmentType: "picture",
|
|
542
550
|
triggerTypes: ["MD", "people", "vehicle"],
|