@camstack/addon-provider-reolink 1.2.87 → 1.2.88
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 +74 -1
- package/dist/addon.mjs +74 -1
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -13648,7 +13648,12 @@ var ConfigEntrySchema = object({
|
|
|
13648
13648
|
value: unknown(),
|
|
13649
13649
|
description: string().optional()
|
|
13650
13650
|
});
|
|
13651
|
-
|
|
13651
|
+
/**
|
|
13652
|
+
* Only `manual` since D356: the operator picks, nothing links itself. The
|
|
13653
|
+
* field survives on the wire because a viewer already OTA'd parses it —
|
|
13654
|
+
* drop it once no shipped client reads `mode`.
|
|
13655
|
+
*/
|
|
13656
|
+
var LinkedDevicesModeSchema = _enum(["manual"]);
|
|
13652
13657
|
/** One resolved linked device — the compact projection consumers need. */
|
|
13653
13658
|
var LinkedDeviceSchema = object({
|
|
13654
13659
|
deviceId: number(),
|
|
@@ -34222,6 +34227,17 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
34222
34227
|
return toDeviceSummary(device, this.addonId);
|
|
34223
34228
|
}
|
|
34224
34229
|
};
|
|
34230
|
+
/**
|
|
34231
|
+
* Default silence budget before a sleeping battery camera is called gone.
|
|
34232
|
+
*
|
|
34233
|
+
* Sized off the mechanism that produces contact, not off taste: a battery cam
|
|
34234
|
+
* on this deployment surfaces a firmware push (battery level, sleep/wake, or a
|
|
34235
|
+
* motion email) on the order of hours even with no visitors, and the snapshot
|
|
34236
|
+
* wrapper's own battery window is 1 hour. Six hours is therefore several
|
|
34237
|
+
* missed opportunities, not one — so a single quiet night does not raise a
|
|
34238
|
+
* fault, and a genuinely flat camera is named well inside a day.
|
|
34239
|
+
*/
|
|
34240
|
+
var BATTERY_UNREACHABLE_AFTER_MS = 360 * 6e4;
|
|
34225
34241
|
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
34226
34242
|
new Set(Object.values(DeviceType));
|
|
34227
34243
|
DeviceFeature.BatteryOperated;
|
|
@@ -231810,6 +231826,15 @@ function reportsPowerSource(info) {
|
|
|
231810
231826
|
return info.adapterStatus !== void 0 || info.chargeStatus !== void 0;
|
|
231811
231827
|
}
|
|
231812
231828
|
//#endregion
|
|
231829
|
+
//#region src/battery-contact-expiry.ts
|
|
231830
|
+
function shouldWakeForContact(input) {
|
|
231831
|
+
if (input.hubChild) return false;
|
|
231832
|
+
if (!input.sleeping) return false;
|
|
231833
|
+
const last = input.lastContactAt;
|
|
231834
|
+
if (typeof last !== "number" || last <= 0) return false;
|
|
231835
|
+
return input.nowMs - last + input.tickMs >= input.unreachableAfterMs;
|
|
231836
|
+
}
|
|
231837
|
+
//#endregion
|
|
231813
231838
|
//#region src/log-channels.ts
|
|
231814
231839
|
/**
|
|
231815
231840
|
* The diagnostic log CHANNELS `provider-reolink` declares.
|
|
@@ -240470,6 +240495,17 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
240470
240495
|
const cycle = (async () => {
|
|
240471
240496
|
try {
|
|
240472
240497
|
if (this.isBattery && this.sleeping) {
|
|
240498
|
+
if (shouldWakeForContact({
|
|
240499
|
+
nowMs: Date.now(),
|
|
240500
|
+
lastContactAt: this.state.battery.lastContactAt,
|
|
240501
|
+
sleeping: true,
|
|
240502
|
+
hubChild: this.isHubChild(),
|
|
240503
|
+
unreachableAfterMs: 216e5,
|
|
240504
|
+
tickMs: ReolinkCamera.BATTERY_UPDATE_INTERVAL_MS
|
|
240505
|
+
})) {
|
|
240506
|
+
await this.wakeForContactRefresh();
|
|
240507
|
+
return;
|
|
240508
|
+
}
|
|
240473
240509
|
this.ctx.logger.debug("battery-update: cam sleeping — skipping cycle without connecting", { tags: { deviceId: this.id } });
|
|
240474
240510
|
return;
|
|
240475
240511
|
}
|
|
@@ -240514,6 +240550,43 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
240514
240550
|
this.batteryUpdateInFlight = cycle;
|
|
240515
240551
|
return cycle;
|
|
240516
240552
|
}
|
|
240553
|
+
/**
|
|
240554
|
+
* D355: wake a standalone battery camera ONCE because its last passive
|
|
240555
|
+
* contact is about to expire, and refresh every slice while it is up.
|
|
240556
|
+
* Bounded by `canProactivelyWake` (the shared cooldown) and by the fact
|
|
240557
|
+
* that a wake that answers resets the silence. A wake that fails is left
|
|
240558
|
+
* alone: the silence then reaches the budget and `deriveBatteryPresence`
|
|
240559
|
+
* says `unreachable` — for the first time on evidence.
|
|
240560
|
+
*/
|
|
240561
|
+
async wakeForContactRefresh() {
|
|
240562
|
+
if (!this.canProactivelyWake("contact-expiry")) return;
|
|
240563
|
+
this.markWakeIssued();
|
|
240564
|
+
const lastContactAt = this.state.battery.lastContactAt ?? 0;
|
|
240565
|
+
const silenceMs = Date.now() - lastContactAt;
|
|
240566
|
+
this.ctx.logger.info("battery contact expiring — waking once to refresh every slice (D355)", {
|
|
240567
|
+
tags: { deviceId: this.id },
|
|
240568
|
+
meta: {
|
|
240569
|
+
silenceMs,
|
|
240570
|
+
budgetMs: BATTERY_UNREACHABLE_AFTER_MS
|
|
240571
|
+
}
|
|
240572
|
+
});
|
|
240573
|
+
try {
|
|
240574
|
+
await this.ensureApi();
|
|
240575
|
+
} catch (err) {
|
|
240576
|
+
this.ctx.logger.warn("battery contact wake FAILED — silence continues and the camera will read unreachable at the budget", {
|
|
240577
|
+
tags: { deviceId: this.id },
|
|
240578
|
+
meta: {
|
|
240579
|
+
silenceMs,
|
|
240580
|
+
error: err instanceof Error ? err.message : String(err)
|
|
240581
|
+
}
|
|
240582
|
+
});
|
|
240583
|
+
return;
|
|
240584
|
+
}
|
|
240585
|
+
await this.refreshBatteryFromApi("demand").catch(() => {});
|
|
240586
|
+
await this.warmCapSlicesOnWake().catch(() => {});
|
|
240587
|
+
await this.alignAuxDevicesState("wake").catch(() => {});
|
|
240588
|
+
await this.warmSnapshotOnWake().catch(() => {});
|
|
240589
|
+
}
|
|
240517
240590
|
/** Arm the periodic battery-cam refresh timer. No-op for wired cams
|
|
240518
240591
|
* (their state is kept fresh by the 10 s aux-align poll and push
|
|
240519
240592
|
* events). Idempotent. */
|
package/dist/addon.mjs
CHANGED
|
@@ -13643,7 +13643,12 @@ var ConfigEntrySchema = object({
|
|
|
13643
13643
|
value: unknown(),
|
|
13644
13644
|
description: string().optional()
|
|
13645
13645
|
});
|
|
13646
|
-
|
|
13646
|
+
/**
|
|
13647
|
+
* Only `manual` since D356: the operator picks, nothing links itself. The
|
|
13648
|
+
* field survives on the wire because a viewer already OTA'd parses it —
|
|
13649
|
+
* drop it once no shipped client reads `mode`.
|
|
13650
|
+
*/
|
|
13651
|
+
var LinkedDevicesModeSchema = _enum(["manual"]);
|
|
13647
13652
|
/** One resolved linked device — the compact projection consumers need. */
|
|
13648
13653
|
var LinkedDeviceSchema = object({
|
|
13649
13654
|
deviceId: number(),
|
|
@@ -34217,6 +34222,17 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
34217
34222
|
return toDeviceSummary(device, this.addonId);
|
|
34218
34223
|
}
|
|
34219
34224
|
};
|
|
34225
|
+
/**
|
|
34226
|
+
* Default silence budget before a sleeping battery camera is called gone.
|
|
34227
|
+
*
|
|
34228
|
+
* Sized off the mechanism that produces contact, not off taste: a battery cam
|
|
34229
|
+
* on this deployment surfaces a firmware push (battery level, sleep/wake, or a
|
|
34230
|
+
* motion email) on the order of hours even with no visitors, and the snapshot
|
|
34231
|
+
* wrapper's own battery window is 1 hour. Six hours is therefore several
|
|
34232
|
+
* missed opportunities, not one — so a single quiet night does not raise a
|
|
34233
|
+
* fault, and a genuinely flat camera is named well inside a day.
|
|
34234
|
+
*/
|
|
34235
|
+
var BATTERY_UNREACHABLE_AFTER_MS = 360 * 6e4;
|
|
34220
34236
|
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
34221
34237
|
new Set(Object.values(DeviceType));
|
|
34222
34238
|
DeviceFeature.BatteryOperated;
|
|
@@ -231790,6 +231806,15 @@ function reportsPowerSource(info) {
|
|
|
231790
231806
|
return info.adapterStatus !== void 0 || info.chargeStatus !== void 0;
|
|
231791
231807
|
}
|
|
231792
231808
|
//#endregion
|
|
231809
|
+
//#region src/battery-contact-expiry.ts
|
|
231810
|
+
function shouldWakeForContact(input) {
|
|
231811
|
+
if (input.hubChild) return false;
|
|
231812
|
+
if (!input.sleeping) return false;
|
|
231813
|
+
const last = input.lastContactAt;
|
|
231814
|
+
if (typeof last !== "number" || last <= 0) return false;
|
|
231815
|
+
return input.nowMs - last + input.tickMs >= input.unreachableAfterMs;
|
|
231816
|
+
}
|
|
231817
|
+
//#endregion
|
|
231793
231818
|
//#region src/log-channels.ts
|
|
231794
231819
|
/**
|
|
231795
231820
|
* The diagnostic log CHANNELS `provider-reolink` declares.
|
|
@@ -240450,6 +240475,17 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
240450
240475
|
const cycle = (async () => {
|
|
240451
240476
|
try {
|
|
240452
240477
|
if (this.isBattery && this.sleeping) {
|
|
240478
|
+
if (shouldWakeForContact({
|
|
240479
|
+
nowMs: Date.now(),
|
|
240480
|
+
lastContactAt: this.state.battery.lastContactAt,
|
|
240481
|
+
sleeping: true,
|
|
240482
|
+
hubChild: this.isHubChild(),
|
|
240483
|
+
unreachableAfterMs: 216e5,
|
|
240484
|
+
tickMs: ReolinkCamera.BATTERY_UPDATE_INTERVAL_MS
|
|
240485
|
+
})) {
|
|
240486
|
+
await this.wakeForContactRefresh();
|
|
240487
|
+
return;
|
|
240488
|
+
}
|
|
240453
240489
|
this.ctx.logger.debug("battery-update: cam sleeping — skipping cycle without connecting", { tags: { deviceId: this.id } });
|
|
240454
240490
|
return;
|
|
240455
240491
|
}
|
|
@@ -240494,6 +240530,43 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
240494
240530
|
this.batteryUpdateInFlight = cycle;
|
|
240495
240531
|
return cycle;
|
|
240496
240532
|
}
|
|
240533
|
+
/**
|
|
240534
|
+
* D355: wake a standalone battery camera ONCE because its last passive
|
|
240535
|
+
* contact is about to expire, and refresh every slice while it is up.
|
|
240536
|
+
* Bounded by `canProactivelyWake` (the shared cooldown) and by the fact
|
|
240537
|
+
* that a wake that answers resets the silence. A wake that fails is left
|
|
240538
|
+
* alone: the silence then reaches the budget and `deriveBatteryPresence`
|
|
240539
|
+
* says `unreachable` — for the first time on evidence.
|
|
240540
|
+
*/
|
|
240541
|
+
async wakeForContactRefresh() {
|
|
240542
|
+
if (!this.canProactivelyWake("contact-expiry")) return;
|
|
240543
|
+
this.markWakeIssued();
|
|
240544
|
+
const lastContactAt = this.state.battery.lastContactAt ?? 0;
|
|
240545
|
+
const silenceMs = Date.now() - lastContactAt;
|
|
240546
|
+
this.ctx.logger.info("battery contact expiring — waking once to refresh every slice (D355)", {
|
|
240547
|
+
tags: { deviceId: this.id },
|
|
240548
|
+
meta: {
|
|
240549
|
+
silenceMs,
|
|
240550
|
+
budgetMs: BATTERY_UNREACHABLE_AFTER_MS
|
|
240551
|
+
}
|
|
240552
|
+
});
|
|
240553
|
+
try {
|
|
240554
|
+
await this.ensureApi();
|
|
240555
|
+
} catch (err) {
|
|
240556
|
+
this.ctx.logger.warn("battery contact wake FAILED — silence continues and the camera will read unreachable at the budget", {
|
|
240557
|
+
tags: { deviceId: this.id },
|
|
240558
|
+
meta: {
|
|
240559
|
+
silenceMs,
|
|
240560
|
+
error: err instanceof Error ? err.message : String(err)
|
|
240561
|
+
}
|
|
240562
|
+
});
|
|
240563
|
+
return;
|
|
240564
|
+
}
|
|
240565
|
+
await this.refreshBatteryFromApi("demand").catch(() => {});
|
|
240566
|
+
await this.warmCapSlicesOnWake().catch(() => {});
|
|
240567
|
+
await this.alignAuxDevicesState("wake").catch(() => {});
|
|
240568
|
+
await this.warmSnapshotOnWake().catch(() => {});
|
|
240569
|
+
}
|
|
240497
240570
|
/** Arm the periodic battery-cam refresh timer. No-op for wired cams
|
|
240498
240571
|
* (their state is kept fresh by the 10 s aux-align poll and push
|
|
240499
240572
|
* events). Idempotent. */
|