@camstack/addon-provider-reolink 1.2.32 → 1.2.34
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 +51 -2
- package/dist/addon.mjs +51 -2
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -230953,6 +230953,8 @@ 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;
|
|
230956
230958
|
try {
|
|
230957
230959
|
await Promise.race([(async () => {
|
|
230958
230960
|
await api.wakeUp(channel, {
|
|
@@ -230960,7 +230962,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230960
230962
|
attempts: 2
|
|
230961
230963
|
});
|
|
230962
230964
|
await sleep$1(1500);
|
|
230963
|
-
|
|
230965
|
+
if (isHubChild) {
|
|
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))]);
|
|
230964
230970
|
const CONFIRM_TIMEOUT_MS = 1e4;
|
|
230965
230971
|
const CONFIRM_POLL_MS = 1e3;
|
|
230966
230972
|
const confirmDeadline = Date.now() + CONFIRM_TIMEOUT_MS;
|
|
@@ -231002,6 +231008,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
231002
231008
|
tags: { deviceId: this.id },
|
|
231003
231009
|
meta: { confirmTimeoutMs: CONFIRM_TIMEOUT_MS }
|
|
231004
231010
|
});
|
|
231011
|
+
this.emitWakeSettled();
|
|
231005
231012
|
return {
|
|
231006
231013
|
awoke: false,
|
|
231007
231014
|
durationMs: Date.now() - startedAt
|
|
@@ -231019,6 +231026,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
231019
231026
|
error: err instanceof Error ? err.message : String(err)
|
|
231020
231027
|
}
|
|
231021
231028
|
});
|
|
231029
|
+
this.emitWakeSettled();
|
|
231022
231030
|
return {
|
|
231023
231031
|
awoke: false,
|
|
231024
231032
|
durationMs: Date.now() - startedAt
|
|
@@ -231184,6 +231192,26 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
231184
231192
|
this.lastProactiveWakeAt = Date.now();
|
|
231185
231193
|
}
|
|
231186
231194
|
/**
|
|
231195
|
+
* Close the transient "waking" window on a wake that did NOT produce a
|
|
231196
|
+
* committed transition (ACK with no awake evidence, or a timeout).
|
|
231197
|
+
* `BatteryOnWakeStarted` opens it; normally the `sleeping: false` commit
|
|
231198
|
+
* closes it via `BatteryOnStatusChanged` — but a failed wake changes no
|
|
231199
|
+
* state, so nothing ever closes it, and listeners (the snapshot overlay,
|
|
231200
|
+
* the broker's "WAKING UP" placeholder) kept showing WAKING for the whole
|
|
231201
|
+
* 35 s TTL after the answer was already known (2026-08-15: the overlay
|
|
231202
|
+
* flapped sleeping↔waking on every retry — read as "random"). Re-asserting
|
|
231203
|
+
* the unchanged slice still emits the event (the runtime-state bridge
|
|
231204
|
+
* re-emits per WRITE), which is exactly the "wake is over, nothing came of
|
|
231205
|
+
* it" signal those windows listen for.
|
|
231206
|
+
*/
|
|
231207
|
+
emitWakeSettled() {
|
|
231208
|
+
if (!this.isBattery) return;
|
|
231209
|
+
this.ctx.eventBus.emit(createEvent(EventCategory.BatteryOnStatusChanged, this.eventSource(), {
|
|
231210
|
+
deviceId: this.id,
|
|
231211
|
+
status: this.state.battery
|
|
231212
|
+
}));
|
|
231213
|
+
}
|
|
231214
|
+
/**
|
|
231187
231215
|
* Gate for a PROACTIVE camera read, checked BEFORE `ensureApi()`.
|
|
231188
231216
|
*
|
|
231189
231217
|
* The login itself is the wake. On a sleeping UDP/battery camera the
|
|
@@ -236683,6 +236711,13 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
236683
236711
|
this.ensureApi().catch((err) => {
|
|
236684
236712
|
this.ctx.logger.warn("Reolink Hub initial connect failed — will retry", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
236685
236713
|
});
|
|
236714
|
+
this.eventUnsubscribers.push(this.ctx.eventBus.subscribe({ category: EventCategory.DeviceRegistered }, (event) => {
|
|
236715
|
+
if (event.data.parentDeviceId !== this.id) return;
|
|
236716
|
+
(async () => {
|
|
236717
|
+
const byChannel = await this.loadAdoptedChildrenByChannel();
|
|
236718
|
+
for (const [ch, did] of byChannel) this.channelToDeviceId.set(ch, did);
|
|
236719
|
+
})().catch(() => {});
|
|
236720
|
+
}));
|
|
236686
236721
|
this.eventUnsubscribers.push(this.ctx.eventBus.subscribe({ category: EventCategory.DeviceUnregistered }, (event) => {
|
|
236687
236722
|
const data = event.data;
|
|
236688
236723
|
if (data.parentDeviceId !== this.id) return;
|
|
@@ -236695,6 +236730,9 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
236695
236730
|
}));
|
|
236696
236731
|
}
|
|
236697
236732
|
eventUnsubscribers = [];
|
|
236733
|
+
/** Per-channel throttle for the unrouted-event warning (see
|
|
236734
|
+
* `routeSimpleEvent`) — a chatty unmapped channel must not flood. */
|
|
236735
|
+
unroutedChannelLoggedAt = /* @__PURE__ */ new Map();
|
|
236698
236736
|
async removeDevice() {
|
|
236699
236737
|
this.shutdownRequested = true;
|
|
236700
236738
|
if (this.reconnectTimer) {
|
|
@@ -237251,7 +237289,18 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
237251
237289
|
const channel = ev?.channel;
|
|
237252
237290
|
if (typeof channel !== "number") return;
|
|
237253
237291
|
const deviceId = this.channelToDeviceId.get(channel);
|
|
237254
|
-
if (deviceId === void 0)
|
|
237292
|
+
if (deviceId === void 0) {
|
|
237293
|
+
const last = this.unroutedChannelLoggedAt.get(channel) ?? 0;
|
|
237294
|
+
const now = Date.now();
|
|
237295
|
+
if (now - last > 6e4) {
|
|
237296
|
+
this.unroutedChannelLoggedAt.set(channel, now);
|
|
237297
|
+
this.ctx.logger.warn("Reolink Hub: simpleEvent for an unmapped channel dropped", { meta: {
|
|
237298
|
+
channel,
|
|
237299
|
+
type: ev?.type ?? "unknown"
|
|
237300
|
+
} });
|
|
237301
|
+
}
|
|
237302
|
+
return;
|
|
237303
|
+
}
|
|
237255
237304
|
this.ctx.devices.getAll().then((all) => all.find((d) => d.id === deviceId)).then((child) => {
|
|
237256
237305
|
if (!(child instanceof ReolinkCamera)) return;
|
|
237257
237306
|
child.handleSimpleEvent(ev);
|
package/dist/addon.mjs
CHANGED
|
@@ -230933,6 +230933,8 @@ 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;
|
|
230936
230938
|
try {
|
|
230937
230939
|
await Promise.race([(async () => {
|
|
230938
230940
|
await api.wakeUp(channel, {
|
|
@@ -230940,7 +230942,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230940
230942
|
attempts: 2
|
|
230941
230943
|
});
|
|
230942
230944
|
await sleep$1(1500);
|
|
230943
|
-
|
|
230945
|
+
if (isHubChild) {
|
|
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))]);
|
|
230944
230950
|
const CONFIRM_TIMEOUT_MS = 1e4;
|
|
230945
230951
|
const CONFIRM_POLL_MS = 1e3;
|
|
230946
230952
|
const confirmDeadline = Date.now() + CONFIRM_TIMEOUT_MS;
|
|
@@ -230982,6 +230988,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230982
230988
|
tags: { deviceId: this.id },
|
|
230983
230989
|
meta: { confirmTimeoutMs: CONFIRM_TIMEOUT_MS }
|
|
230984
230990
|
});
|
|
230991
|
+
this.emitWakeSettled();
|
|
230985
230992
|
return {
|
|
230986
230993
|
awoke: false,
|
|
230987
230994
|
durationMs: Date.now() - startedAt
|
|
@@ -230999,6 +231006,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
230999
231006
|
error: err instanceof Error ? err.message : String(err)
|
|
231000
231007
|
}
|
|
231001
231008
|
});
|
|
231009
|
+
this.emitWakeSettled();
|
|
231002
231010
|
return {
|
|
231003
231011
|
awoke: false,
|
|
231004
231012
|
durationMs: Date.now() - startedAt
|
|
@@ -231164,6 +231172,26 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
231164
231172
|
this.lastProactiveWakeAt = Date.now();
|
|
231165
231173
|
}
|
|
231166
231174
|
/**
|
|
231175
|
+
* Close the transient "waking" window on a wake that did NOT produce a
|
|
231176
|
+
* committed transition (ACK with no awake evidence, or a timeout).
|
|
231177
|
+
* `BatteryOnWakeStarted` opens it; normally the `sleeping: false` commit
|
|
231178
|
+
* closes it via `BatteryOnStatusChanged` — but a failed wake changes no
|
|
231179
|
+
* state, so nothing ever closes it, and listeners (the snapshot overlay,
|
|
231180
|
+
* the broker's "WAKING UP" placeholder) kept showing WAKING for the whole
|
|
231181
|
+
* 35 s TTL after the answer was already known (2026-08-15: the overlay
|
|
231182
|
+
* flapped sleeping↔waking on every retry — read as "random"). Re-asserting
|
|
231183
|
+
* the unchanged slice still emits the event (the runtime-state bridge
|
|
231184
|
+
* re-emits per WRITE), which is exactly the "wake is over, nothing came of
|
|
231185
|
+
* it" signal those windows listen for.
|
|
231186
|
+
*/
|
|
231187
|
+
emitWakeSettled() {
|
|
231188
|
+
if (!this.isBattery) return;
|
|
231189
|
+
this.ctx.eventBus.emit(createEvent(EventCategory.BatteryOnStatusChanged, this.eventSource(), {
|
|
231190
|
+
deviceId: this.id,
|
|
231191
|
+
status: this.state.battery
|
|
231192
|
+
}));
|
|
231193
|
+
}
|
|
231194
|
+
/**
|
|
231167
231195
|
* Gate for a PROACTIVE camera read, checked BEFORE `ensureApi()`.
|
|
231168
231196
|
*
|
|
231169
231197
|
* The login itself is the wake. On a sleeping UDP/battery camera the
|
|
@@ -236663,6 +236691,13 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
236663
236691
|
this.ensureApi().catch((err) => {
|
|
236664
236692
|
this.ctx.logger.warn("Reolink Hub initial connect failed — will retry", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
236665
236693
|
});
|
|
236694
|
+
this.eventUnsubscribers.push(this.ctx.eventBus.subscribe({ category: EventCategory.DeviceRegistered }, (event) => {
|
|
236695
|
+
if (event.data.parentDeviceId !== this.id) return;
|
|
236696
|
+
(async () => {
|
|
236697
|
+
const byChannel = await this.loadAdoptedChildrenByChannel();
|
|
236698
|
+
for (const [ch, did] of byChannel) this.channelToDeviceId.set(ch, did);
|
|
236699
|
+
})().catch(() => {});
|
|
236700
|
+
}));
|
|
236666
236701
|
this.eventUnsubscribers.push(this.ctx.eventBus.subscribe({ category: EventCategory.DeviceUnregistered }, (event) => {
|
|
236667
236702
|
const data = event.data;
|
|
236668
236703
|
if (data.parentDeviceId !== this.id) return;
|
|
@@ -236675,6 +236710,9 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
236675
236710
|
}));
|
|
236676
236711
|
}
|
|
236677
236712
|
eventUnsubscribers = [];
|
|
236713
|
+
/** Per-channel throttle for the unrouted-event warning (see
|
|
236714
|
+
* `routeSimpleEvent`) — a chatty unmapped channel must not flood. */
|
|
236715
|
+
unroutedChannelLoggedAt = /* @__PURE__ */ new Map();
|
|
236678
236716
|
async removeDevice() {
|
|
236679
236717
|
this.shutdownRequested = true;
|
|
236680
236718
|
if (this.reconnectTimer) {
|
|
@@ -237231,7 +237269,18 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
237231
237269
|
const channel = ev?.channel;
|
|
237232
237270
|
if (typeof channel !== "number") return;
|
|
237233
237271
|
const deviceId = this.channelToDeviceId.get(channel);
|
|
237234
|
-
if (deviceId === void 0)
|
|
237272
|
+
if (deviceId === void 0) {
|
|
237273
|
+
const last = this.unroutedChannelLoggedAt.get(channel) ?? 0;
|
|
237274
|
+
const now = Date.now();
|
|
237275
|
+
if (now - last > 6e4) {
|
|
237276
|
+
this.unroutedChannelLoggedAt.set(channel, now);
|
|
237277
|
+
this.ctx.logger.warn("Reolink Hub: simpleEvent for an unmapped channel dropped", { meta: {
|
|
237278
|
+
channel,
|
|
237279
|
+
type: ev?.type ?? "unknown"
|
|
237280
|
+
} });
|
|
237281
|
+
}
|
|
237282
|
+
return;
|
|
237283
|
+
}
|
|
237235
237284
|
this.ctx.devices.getAll().then((all) => all.find((d) => d.id === deviceId)).then((child) => {
|
|
237236
237285
|
if (!(child instanceof ReolinkCamera)) return;
|
|
237237
237286
|
child.handleSimpleEvent(ev);
|