@camstack/addon-provider-reolink 1.2.34 → 1.2.36
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/addon.js +49 -9
- package/dist/addon.mjs +49 -9
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -230953,8 +230953,6 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230953
230953
|
});
|
|
230954
230954
|
this.ctx.eventBus.emit(createEvent(EventCategory.BatteryOnWakeStarted, this.eventSource(), { deviceId: this.id }));
|
|
230955
230955
|
const channel = this.getChannel();
|
|
230956
|
-
const isHubChild = this.isHubChild();
|
|
230957
|
-
const wakeTimeoutMs = isHubChild ? Math.max(timeoutMs, 2e4) : timeoutMs;
|
|
230958
230956
|
try {
|
|
230959
230957
|
await Promise.race([(async () => {
|
|
230960
230958
|
await api.wakeUp(channel, {
|
|
@@ -230962,20 +230960,19 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230962
230960
|
attempts: 2
|
|
230963
230961
|
});
|
|
230964
230962
|
await sleep$1(1500);
|
|
230965
|
-
|
|
230966
|
-
const dialId = buildCamStreamId("native", channel, "main", 1);
|
|
230967
|
-
await Promise.race([this.ensureRfc4571Server(dialId, channel, "main"), sleep$1(1e4)]);
|
|
230968
|
-
}
|
|
230969
|
-
})(), new Promise((_, rej) => setTimeout(() => rej(/* @__PURE__ */ new Error("wakeForStream timeout")), wakeTimeoutMs))]);
|
|
230963
|
+
})(), new Promise((_, rej) => setTimeout(() => rej(/* @__PURE__ */ new Error("wakeForStream timeout")), timeoutMs))]);
|
|
230970
230964
|
const CONFIRM_TIMEOUT_MS = 1e4;
|
|
230971
230965
|
const CONFIRM_POLL_MS = 1e3;
|
|
230972
230966
|
const confirmDeadline = Date.now() + CONFIRM_TIMEOUT_MS;
|
|
230973
230967
|
const parent = await this.getParentHub();
|
|
230974
230968
|
let confirmed = false;
|
|
230969
|
+
let observedAwake = false;
|
|
230975
230970
|
while (Date.now() < confirmDeadline) {
|
|
230976
230971
|
if (parent !== null) try {
|
|
230977
|
-
|
|
230972
|
+
const entry = (await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel());
|
|
230973
|
+
if (entry !== void 0 && entry.online !== false) {
|
|
230978
230974
|
confirmed = true;
|
|
230975
|
+
observedAwake = entry.sleeping === false;
|
|
230979
230976
|
break;
|
|
230980
230977
|
}
|
|
230981
230978
|
} catch {}
|
|
@@ -230988,13 +230985,14 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230988
230985
|
}
|
|
230989
230986
|
if (state === "awake") {
|
|
230990
230987
|
confirmed = true;
|
|
230988
|
+
observedAwake = true;
|
|
230991
230989
|
break;
|
|
230992
230990
|
}
|
|
230993
230991
|
}
|
|
230994
230992
|
await sleep$1(CONFIRM_POLL_MS);
|
|
230995
230993
|
}
|
|
230996
230994
|
const confirmSource = parent !== null ? "hub-summary" : "sleep-poll";
|
|
230997
|
-
if (
|
|
230995
|
+
if (observedAwake && this.commitSleepState(false, confirmSource)) {
|
|
230998
230996
|
this.ctx.logger.info("battery wakeForStream: wake confirmed — driving wake transition", {
|
|
230999
230997
|
tags: { deviceId: this.id },
|
|
231000
230998
|
meta: {
|
|
@@ -233632,8 +233630,50 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
233632
233630
|
* drained the battery and, by bursting the socket, was itself what starved
|
|
233633
233631
|
* GetEnc.
|
|
233634
233632
|
*/
|
|
233633
|
+
/**
|
|
233634
|
+
* The catalog a SLEEPING hub child can still offer: the parent's RTSP
|
|
233635
|
+
* relay entries, derived from the parent's config (host + credentials +
|
|
233636
|
+
* the Reolink Hub's per-channel relay scheme), with zero contact to the
|
|
233637
|
+
* child. This is the difference between a sleeping hub child being
|
|
233638
|
+
* playable and being a permanent "sleeping" tile: the broker gets a
|
|
233639
|
+
* dialable URL, the relay dial wakes the camera over RF (verified live
|
|
233640
|
+
* against the Home Hub, 2026-08-15), and the catalog never depended on
|
|
233641
|
+
* the child being awake to build.
|
|
233642
|
+
*/
|
|
233643
|
+
async buildHubRelayDescriptors() {
|
|
233644
|
+
if (!this.isHubChild()) return [];
|
|
233645
|
+
const parentId = this.parentDeviceId;
|
|
233646
|
+
if (parentId === null) return [];
|
|
233647
|
+
const cfg = (await this.ctx.devices.getAll()).find((d) => d.id === parentId)?.config.values;
|
|
233648
|
+
const host = cfg?.host;
|
|
233649
|
+
if (typeof host !== "string" || host.length === 0) return [];
|
|
233650
|
+
const user = encodeURIComponent(String(cfg?.username ?? ""));
|
|
233651
|
+
const password = encodeURIComponent(String(cfg?.password ?? ""));
|
|
233652
|
+
const port = typeof cfg?.port === "number" && cfg.port > 0 ? cfg.port : 554;
|
|
233653
|
+
const channel = this.getChannel();
|
|
233654
|
+
const channelCount = this.channelCount();
|
|
233655
|
+
const relayChannel = channel + 1;
|
|
233656
|
+
const out = [];
|
|
233657
|
+
for (const profile of ["main", "sub"]) out.push({
|
|
233658
|
+
camStreamId: buildCamStreamId("rtsp", channel, profile, channelCount),
|
|
233659
|
+
kind: "pull-rtsp",
|
|
233660
|
+
label: `Hub relay (${profile})`,
|
|
233661
|
+
url: `rtsp://${user}:${password}@${host}:${port}/h264Preview_0${relayChannel}_${profile}`,
|
|
233662
|
+
autoEligible: true,
|
|
233663
|
+
deviceFeatures: [...this.features]
|
|
233664
|
+
});
|
|
233665
|
+
return out;
|
|
233666
|
+
}
|
|
233635
233667
|
async buildStreamCatalogUncached() {
|
|
233636
233668
|
if (this.isBattery && this.sleeping) {
|
|
233669
|
+
const relay = await this.buildHubRelayDescriptors().catch(() => []);
|
|
233670
|
+
if (relay.length > 0) {
|
|
233671
|
+
this.ctx.logger.debug("buildStreamCatalog: sleeping hub child — serving hub relay entries", {
|
|
233672
|
+
tags: { deviceId: this.id },
|
|
233673
|
+
meta: { entries: relay.map((r) => r.camStreamId) }
|
|
233674
|
+
});
|
|
233675
|
+
return relay;
|
|
233676
|
+
}
|
|
233637
233677
|
this.ctx.logger.debug("buildStreamCatalog: battery cam sleeping, no cache — deferring to wake", { tags: { deviceId: this.id } });
|
|
233638
233678
|
return [];
|
|
233639
233679
|
}
|
package/dist/addon.mjs
CHANGED
|
@@ -230933,8 +230933,6 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230933
230933
|
});
|
|
230934
230934
|
this.ctx.eventBus.emit(createEvent(EventCategory.BatteryOnWakeStarted, this.eventSource(), { deviceId: this.id }));
|
|
230935
230935
|
const channel = this.getChannel();
|
|
230936
|
-
const isHubChild = this.isHubChild();
|
|
230937
|
-
const wakeTimeoutMs = isHubChild ? Math.max(timeoutMs, 2e4) : timeoutMs;
|
|
230938
230936
|
try {
|
|
230939
230937
|
await Promise.race([(async () => {
|
|
230940
230938
|
await api.wakeUp(channel, {
|
|
@@ -230942,20 +230940,19 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230942
230940
|
attempts: 2
|
|
230943
230941
|
});
|
|
230944
230942
|
await sleep$1(1500);
|
|
230945
|
-
|
|
230946
|
-
const dialId = buildCamStreamId("native", channel, "main", 1);
|
|
230947
|
-
await Promise.race([this.ensureRfc4571Server(dialId, channel, "main"), sleep$1(1e4)]);
|
|
230948
|
-
}
|
|
230949
|
-
})(), new Promise((_, rej) => setTimeout(() => rej(/* @__PURE__ */ new Error("wakeForStream timeout")), wakeTimeoutMs))]);
|
|
230943
|
+
})(), new Promise((_, rej) => setTimeout(() => rej(/* @__PURE__ */ new Error("wakeForStream timeout")), timeoutMs))]);
|
|
230950
230944
|
const CONFIRM_TIMEOUT_MS = 1e4;
|
|
230951
230945
|
const CONFIRM_POLL_MS = 1e3;
|
|
230952
230946
|
const confirmDeadline = Date.now() + CONFIRM_TIMEOUT_MS;
|
|
230953
230947
|
const parent = await this.getParentHub();
|
|
230954
230948
|
let confirmed = false;
|
|
230949
|
+
let observedAwake = false;
|
|
230955
230950
|
while (Date.now() < confirmDeadline) {
|
|
230956
230951
|
if (parent !== null) try {
|
|
230957
|
-
|
|
230952
|
+
const entry = (await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel());
|
|
230953
|
+
if (entry !== void 0 && entry.online !== false) {
|
|
230958
230954
|
confirmed = true;
|
|
230955
|
+
observedAwake = entry.sleeping === false;
|
|
230959
230956
|
break;
|
|
230960
230957
|
}
|
|
230961
230958
|
} catch {}
|
|
@@ -230968,13 +230965,14 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230968
230965
|
}
|
|
230969
230966
|
if (state === "awake") {
|
|
230970
230967
|
confirmed = true;
|
|
230968
|
+
observedAwake = true;
|
|
230971
230969
|
break;
|
|
230972
230970
|
}
|
|
230973
230971
|
}
|
|
230974
230972
|
await sleep$1(CONFIRM_POLL_MS);
|
|
230975
230973
|
}
|
|
230976
230974
|
const confirmSource = parent !== null ? "hub-summary" : "sleep-poll";
|
|
230977
|
-
if (
|
|
230975
|
+
if (observedAwake && this.commitSleepState(false, confirmSource)) {
|
|
230978
230976
|
this.ctx.logger.info("battery wakeForStream: wake confirmed — driving wake transition", {
|
|
230979
230977
|
tags: { deviceId: this.id },
|
|
230980
230978
|
meta: {
|
|
@@ -233612,8 +233610,50 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
233612
233610
|
* drained the battery and, by bursting the socket, was itself what starved
|
|
233613
233611
|
* GetEnc.
|
|
233614
233612
|
*/
|
|
233613
|
+
/**
|
|
233614
|
+
* The catalog a SLEEPING hub child can still offer: the parent's RTSP
|
|
233615
|
+
* relay entries, derived from the parent's config (host + credentials +
|
|
233616
|
+
* the Reolink Hub's per-channel relay scheme), with zero contact to the
|
|
233617
|
+
* child. This is the difference between a sleeping hub child being
|
|
233618
|
+
* playable and being a permanent "sleeping" tile: the broker gets a
|
|
233619
|
+
* dialable URL, the relay dial wakes the camera over RF (verified live
|
|
233620
|
+
* against the Home Hub, 2026-08-15), and the catalog never depended on
|
|
233621
|
+
* the child being awake to build.
|
|
233622
|
+
*/
|
|
233623
|
+
async buildHubRelayDescriptors() {
|
|
233624
|
+
if (!this.isHubChild()) return [];
|
|
233625
|
+
const parentId = this.parentDeviceId;
|
|
233626
|
+
if (parentId === null) return [];
|
|
233627
|
+
const cfg = (await this.ctx.devices.getAll()).find((d) => d.id === parentId)?.config.values;
|
|
233628
|
+
const host = cfg?.host;
|
|
233629
|
+
if (typeof host !== "string" || host.length === 0) return [];
|
|
233630
|
+
const user = encodeURIComponent(String(cfg?.username ?? ""));
|
|
233631
|
+
const password = encodeURIComponent(String(cfg?.password ?? ""));
|
|
233632
|
+
const port = typeof cfg?.port === "number" && cfg.port > 0 ? cfg.port : 554;
|
|
233633
|
+
const channel = this.getChannel();
|
|
233634
|
+
const channelCount = this.channelCount();
|
|
233635
|
+
const relayChannel = channel + 1;
|
|
233636
|
+
const out = [];
|
|
233637
|
+
for (const profile of ["main", "sub"]) out.push({
|
|
233638
|
+
camStreamId: buildCamStreamId("rtsp", channel, profile, channelCount),
|
|
233639
|
+
kind: "pull-rtsp",
|
|
233640
|
+
label: `Hub relay (${profile})`,
|
|
233641
|
+
url: `rtsp://${user}:${password}@${host}:${port}/h264Preview_0${relayChannel}_${profile}`,
|
|
233642
|
+
autoEligible: true,
|
|
233643
|
+
deviceFeatures: [...this.features]
|
|
233644
|
+
});
|
|
233645
|
+
return out;
|
|
233646
|
+
}
|
|
233615
233647
|
async buildStreamCatalogUncached() {
|
|
233616
233648
|
if (this.isBattery && this.sleeping) {
|
|
233649
|
+
const relay = await this.buildHubRelayDescriptors().catch(() => []);
|
|
233650
|
+
if (relay.length > 0) {
|
|
233651
|
+
this.ctx.logger.debug("buildStreamCatalog: sleeping hub child — serving hub relay entries", {
|
|
233652
|
+
tags: { deviceId: this.id },
|
|
233653
|
+
meta: { entries: relay.map((r) => r.camStreamId) }
|
|
233654
|
+
});
|
|
233655
|
+
return relay;
|
|
233656
|
+
}
|
|
233617
233657
|
this.ctx.logger.debug("buildStreamCatalog: battery cam sleeping, no cache — deferring to wake", { tags: { deviceId: this.id } });
|
|
233618
233658
|
return [];
|
|
233619
233659
|
}
|