@camstack/addon-post-analysis 1.2.661 → 1.2.663
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/CHANGELOG.md +13 -0
- package/dist/{clip-model-registry-CVajwmEk.mjs → clip-model-registry-CwXJyrLg.mjs} +34398 -33387
- package/dist/{clip-model-registry-RvEPUqvS.js → clip-model-registry-Cz8LWYwU.js} +34398 -33387
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CwKrui6c.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-jPBj20ez.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Be6bZvOS.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B5Bw-VHt.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-DR75U6YM.mjs → hostInit-DOdK6KJ5.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +391 -31
- package/dist/pipeline-analytics/index.mjs +391 -31
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BDKliSzv.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BGdtpHOa.mjs +0 -26
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_clip_model_registry = require("../clip-model-registry-
|
|
5
|
+
const require_clip_model_registry = require("../clip-model-registry-Cz8LWYwU.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_clip_model_registry.__toESM(node_fs, 1);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -8950,6 +8950,17 @@ var en_default = {
|
|
|
8950
8950
|
"detection.subject.identity": "{{label}}",
|
|
8951
8951
|
"detection.subject.plate": "{{classNoun}} {{label}}",
|
|
8952
8952
|
"detection.inZones": " in {{zones}}",
|
|
8953
|
+
"appliance.finished.title": "{{device}} finished",
|
|
8954
|
+
"appliance.finished.body": "{{device}} finished{{afterDuration}}{{usedEnergy}}",
|
|
8955
|
+
"appliance.finished.duration": " after {{duration}}",
|
|
8956
|
+
"appliance.finished.energy": " and used {{energy}}",
|
|
8957
|
+
"appliance.duration.minutes": {
|
|
8958
|
+
"one": "{{minutes}} minute",
|
|
8959
|
+
"other": "{{minutes}} minutes"
|
|
8960
|
+
},
|
|
8961
|
+
"appliance.duration.hours": "{{hours}} h",
|
|
8962
|
+
"appliance.duration.hoursMinutes": "{{hours}} h {{minutes}} min",
|
|
8963
|
+
"appliance.energy.value": "{{value}} kWh",
|
|
8953
8964
|
"class.person": {
|
|
8954
8965
|
"one": "person",
|
|
8955
8966
|
"other": "people"
|
|
@@ -9356,6 +9367,17 @@ var it_default = {
|
|
|
9356
9367
|
"detection.subject.identity": "{{label}}",
|
|
9357
9368
|
"detection.subject.plate": "{{classNoun}} {{label}}",
|
|
9358
9369
|
"detection.inZones": " in {{zones}}",
|
|
9370
|
+
"appliance.finished.title": "{{device}} ha terminato",
|
|
9371
|
+
"appliance.finished.body": "{{device}} ha terminato{{afterDuration}}{{usedEnergy}}",
|
|
9372
|
+
"appliance.finished.duration": " dopo {{duration}}",
|
|
9373
|
+
"appliance.finished.energy": " e ha consumato {{energy}}",
|
|
9374
|
+
"appliance.duration.minutes": {
|
|
9375
|
+
"one": "{{minutes}} minuto",
|
|
9376
|
+
"other": "{{minutes}} minuti"
|
|
9377
|
+
},
|
|
9378
|
+
"appliance.duration.hours": "{{hours}} h",
|
|
9379
|
+
"appliance.duration.hoursMinutes": "{{hours}} h {{minutes}} min",
|
|
9380
|
+
"appliance.energy.value": "{{value}} kWh",
|
|
9359
9381
|
"class.person": {
|
|
9360
9382
|
"one": "persona",
|
|
9361
9383
|
"other": "persone"
|
|
@@ -68703,6 +68725,109 @@ function createAnalyticsWidgetsProvider() {
|
|
|
68703
68725
|
] };
|
|
68704
68726
|
}
|
|
68705
68727
|
//#endregion
|
|
68728
|
+
//#region src/notification-center/appliance-cycle.ts
|
|
68729
|
+
var NC_UNKNOWN_CYCLE_FACTS = {
|
|
68730
|
+
durationMs: null,
|
|
68731
|
+
energyKwh: null
|
|
68732
|
+
};
|
|
68733
|
+
var NC_EMPTY_CYCLE_VARS = {
|
|
68734
|
+
duration: "",
|
|
68735
|
+
energy: "",
|
|
68736
|
+
afterDuration: "",
|
|
68737
|
+
usedEnergy: ""
|
|
68738
|
+
};
|
|
68739
|
+
/** `52 minutes` / `1 h 12 min` / `2 h`; `''` below one minute (never "0 minutes"). */
|
|
68740
|
+
function durationText(texts, durationMs) {
|
|
68741
|
+
if (durationMs === null || !Number.isFinite(durationMs)) return "";
|
|
68742
|
+
const totalMinutes = Math.round(durationMs / 6e4);
|
|
68743
|
+
if (totalMinutes < 1) return "";
|
|
68744
|
+
if (totalMinutes < 60) return texts.text({
|
|
68745
|
+
key: "appliance.duration.minutes",
|
|
68746
|
+
count: totalMinutes,
|
|
68747
|
+
vars: { minutes: `${totalMinutes}` }
|
|
68748
|
+
});
|
|
68749
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
68750
|
+
const minutes = totalMinutes % 60;
|
|
68751
|
+
return minutes === 0 ? texts.text({
|
|
68752
|
+
key: "appliance.duration.hours",
|
|
68753
|
+
vars: { hours: `${hours}` }
|
|
68754
|
+
}) : texts.text({
|
|
68755
|
+
key: "appliance.duration.hoursMinutes",
|
|
68756
|
+
vars: {
|
|
68757
|
+
hours: `${hours}`,
|
|
68758
|
+
minutes: `${minutes}`
|
|
68759
|
+
}
|
|
68760
|
+
});
|
|
68761
|
+
}
|
|
68762
|
+
/** `0,84 kWh` (it) / `0.84 kWh` (en); `''` when unmeasured. */
|
|
68763
|
+
function energyText(texts, energyKwh) {
|
|
68764
|
+
if (energyKwh === null || !Number.isFinite(energyKwh) || energyKwh < 0) return "";
|
|
68765
|
+
const value = energyKwh.toLocaleString(texts.language, {
|
|
68766
|
+
minimumFractionDigits: 2,
|
|
68767
|
+
maximumFractionDigits: 2
|
|
68768
|
+
});
|
|
68769
|
+
return texts.text({
|
|
68770
|
+
key: "appliance.energy.value",
|
|
68771
|
+
vars: { value }
|
|
68772
|
+
});
|
|
68773
|
+
}
|
|
68774
|
+
/** The four variables of a finished cycle, fragments rendered from scalars only. */
|
|
68775
|
+
function ncApplianceCycleVars(texts, facts) {
|
|
68776
|
+
const duration = durationText(texts, facts.durationMs);
|
|
68777
|
+
const energy = energyText(texts, facts.energyKwh);
|
|
68778
|
+
return {
|
|
68779
|
+
duration,
|
|
68780
|
+
energy,
|
|
68781
|
+
afterDuration: duration === "" ? "" : texts.text({
|
|
68782
|
+
key: "appliance.finished.duration",
|
|
68783
|
+
vars: { duration }
|
|
68784
|
+
}),
|
|
68785
|
+
usedEnergy: energy === "" ? "" : texts.text({
|
|
68786
|
+
key: "appliance.finished.energy",
|
|
68787
|
+
vars: { energy }
|
|
68788
|
+
})
|
|
68789
|
+
};
|
|
68790
|
+
}
|
|
68791
|
+
/**
|
|
68792
|
+
* The frozen reference a FINISHED appliance cycle row carries (`{}` for every
|
|
68793
|
+
* other row): kind `appliance-cycle`, edge `cleared`. The appliance is the
|
|
68794
|
+
* sensor itself — a linked camera is only where the row was attributed.
|
|
68795
|
+
*/
|
|
68796
|
+
function applianceCycleOf(subject) {
|
|
68797
|
+
if (subject.sensorKind !== "appliance-cycle" || subject.sensorRaised !== false) return {};
|
|
68798
|
+
return { applianceCycle: { deviceId: subject.linkedSensorId ?? subject.sourceDeviceId ?? subject.deviceId } };
|
|
68799
|
+
}
|
|
68800
|
+
//#endregion
|
|
68801
|
+
//#region src/notification-center/appliance-cycle-runs.ts
|
|
68802
|
+
var CYCLE_FACTS_WAIT_MS = 3e3;
|
|
68803
|
+
var CYCLE_FACTS_POLL_MS = 250;
|
|
68804
|
+
/** A closed run belongs to this finish when it ended within this much of it. */
|
|
68805
|
+
var CYCLE_RUN_MATCH_MS = 10 * 6e4;
|
|
68806
|
+
function factsOfClosed(run, finishedAtMs) {
|
|
68807
|
+
if (run.endedAt === null || Math.abs(run.endedAt - finishedAtMs) > CYCLE_RUN_MATCH_MS) return NC_UNKNOWN_CYCLE_FACTS;
|
|
68808
|
+
return {
|
|
68809
|
+
durationMs: run.durationMs,
|
|
68810
|
+
energyKwh: run.detail.energyKwh
|
|
68811
|
+
};
|
|
68812
|
+
}
|
|
68813
|
+
function applianceCycleFactsFromRuns(ports) {
|
|
68814
|
+
return async ({ deviceId, finishedAtMs }) => {
|
|
68815
|
+
let waited = 0;
|
|
68816
|
+
for (;;) {
|
|
68817
|
+
const run = await ports.newestRun(deviceId);
|
|
68818
|
+
if (run === null) return NC_UNKNOWN_CYCLE_FACTS;
|
|
68819
|
+
if (run.state === "closed") return factsOfClosed(run, finishedAtMs);
|
|
68820
|
+
if (run.startedAt > finishedAtMs) return NC_UNKNOWN_CYCLE_FACTS;
|
|
68821
|
+
if (waited >= CYCLE_FACTS_WAIT_MS) return {
|
|
68822
|
+
durationMs: finishedAtMs - run.startedAt,
|
|
68823
|
+
energyKwh: null
|
|
68824
|
+
};
|
|
68825
|
+
await ports.sleep(CYCLE_FACTS_POLL_MS);
|
|
68826
|
+
waited += CYCLE_FACTS_POLL_MS;
|
|
68827
|
+
}
|
|
68828
|
+
};
|
|
68829
|
+
}
|
|
68830
|
+
//#endregion
|
|
68706
68831
|
//#region src/pipeline-analytics/runtime/wire-subscriptions.ts
|
|
68707
68832
|
/**
|
|
68708
68833
|
* Every category the Notification Center's system-event intake can turn into a
|
|
@@ -70664,6 +70789,8 @@ Object.freeze({
|
|
|
70664
70789
|
"page": 1,
|
|
70665
70790
|
"pageSize": 50
|
|
70666
70791
|
} },
|
|
70792
|
+
"device-runs": { "listRuns": { "limit": 50 } },
|
|
70793
|
+
"fan-presets": { "capturePreset": { "steps": [] } },
|
|
70667
70794
|
"llm": { "upsertProfile": { "profile": { "__nested__": {
|
|
70668
70795
|
"timeoutMs": 6e4,
|
|
70669
70796
|
"connectTimeoutMs": 1e4,
|
|
@@ -70904,6 +71031,10 @@ Object.freeze({
|
|
|
70904
71031
|
"speed": 2
|
|
70905
71032
|
}
|
|
70906
71033
|
},
|
|
71034
|
+
"system": { "debugWatch": {
|
|
71035
|
+
"channels": [],
|
|
71036
|
+
"deviceIds": []
|
|
71037
|
+
} },
|
|
70907
71038
|
"terminal-session": { "pullOutput": { "waitMs": 0 } },
|
|
70908
71039
|
"training": {
|
|
70909
71040
|
"planJob": { "selection": { "__nested__": { "workState": "complete" } } },
|
|
@@ -70950,6 +71081,7 @@ Object.freeze({
|
|
|
70950
71081
|
],
|
|
70951
71082
|
"device-removal-hook": ["listDeviceData"],
|
|
70952
71083
|
"failure-contribution": ["list"],
|
|
71084
|
+
"integration-instances": ["listInstances"],
|
|
70953
71085
|
"llm": [
|
|
70954
71086
|
"getDefaults",
|
|
70955
71087
|
"getUsage",
|
|
@@ -70991,6 +71123,7 @@ Object.freeze({
|
|
|
70991
71123
|
"listSupportedEntityKinds",
|
|
70992
71124
|
"unexposeEntity"
|
|
70993
71125
|
],
|
|
71126
|
+
"integration-instances": ["testInstance"],
|
|
70994
71127
|
"log-destination": [
|
|
70995
71128
|
"cancelRead",
|
|
70996
71129
|
"describeRead",
|
|
@@ -85089,6 +85222,9 @@ async function renderMosaic(request, logger) {
|
|
|
85089
85222
|
* one composition are decisions about the set, and none of them belongs in a
|
|
85090
85223
|
* shelf that photographs one camera for an absence.
|
|
85091
85224
|
*
|
|
85225
|
+
* A SLEEPING battery camera is woken by one forced capture when the rule leaves
|
|
85226
|
+
* it allowed (D998) — bounded, once per gap per camera, never by a poll.
|
|
85227
|
+
*
|
|
85092
85228
|
* Two reads can only ever ADD a camera back, never take one away on their own
|
|
85093
85229
|
* failure (D49): a wrapper-state read (run in parallel with the capture) that
|
|
85094
85230
|
* misses or throws keeps the tile, and a freshness read that misses or throws
|
|
@@ -85102,6 +85238,15 @@ var NC_LINKED_CAMERA_PREFIX = "nc-linked:";
|
|
|
85102
85238
|
function isLinkedStillId(id) {
|
|
85103
85239
|
return id.startsWith(NC_LINKED_MOSAIC_PREFIX) || id.startsWith(NC_LINKED_CAMERA_PREFIX);
|
|
85104
85240
|
}
|
|
85241
|
+
/**
|
|
85242
|
+
* D998 — the one forced capture that wakes a sleeping battery camera for a
|
|
85243
|
+
* sensor notification: the bound it may take, the pause between re-polls of a
|
|
85244
|
+
* camera another wake already started, and the gap per camera before it is
|
|
85245
|
+
* woken again (a flapping contact must not drain a battery).
|
|
85246
|
+
*/
|
|
85247
|
+
var NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS = 15e3;
|
|
85248
|
+
var NC_LINKED_WAKE_POLL_MS = 1e3;
|
|
85249
|
+
var NC_LINKED_WAKE_MIN_GAP_MS = 6e4;
|
|
85105
85250
|
/** Per camera — the marker's own bound (`SENSOR_MARKER_SNAPSHOT_TIMEOUT_MS`). */
|
|
85106
85251
|
var SENSOR_LINKED_CAPTURE_TIMEOUT_MS = 2500;
|
|
85107
85252
|
/** The capture-free wrapper-state read, per camera. It runs IN PARALLEL with
|
|
@@ -85134,11 +85279,14 @@ var NcLinkedStillShelf = class {
|
|
|
85134
85279
|
deps;
|
|
85135
85280
|
sets = /* @__PURE__ */ new Map();
|
|
85136
85281
|
owners = /* @__PURE__ */ new Map();
|
|
85282
|
+
/** setId → when its in-flight wake gives up (the dispatcher waits that long). */
|
|
85283
|
+
pendingWakes = /* @__PURE__ */ new Map();
|
|
85284
|
+
lastWakeAt = /* @__PURE__ */ new Map();
|
|
85137
85285
|
constructor(deps) {
|
|
85138
85286
|
this.deps = deps;
|
|
85139
85287
|
}
|
|
85140
85288
|
/** SYNCHRONOUS: the evaluation that follows names these owners. */
|
|
85141
|
-
captureSet(sensorId, cameraIds, atMs) {
|
|
85289
|
+
captureSet(sensorId, cameraIds, atMs, options = { wakeSleeping: false }) {
|
|
85142
85290
|
const now = this.deps.now();
|
|
85143
85291
|
this.prune(now);
|
|
85144
85292
|
const setId = (0, node_crypto.randomUUID)();
|
|
@@ -85166,7 +85314,7 @@ var NcLinkedStillShelf = class {
|
|
|
85166
85314
|
camera: cameraId
|
|
85167
85315
|
});
|
|
85168
85316
|
});
|
|
85169
|
-
this.run(setId, stills, atMs, now).catch((err) => {
|
|
85317
|
+
this.run(setId, stills, atMs, now, options).catch((err) => {
|
|
85170
85318
|
this.deps.logger.warn("sensor notification pictures failed — it ships text-only", {
|
|
85171
85319
|
tags: { deviceId: sensorId },
|
|
85172
85320
|
meta: { error: String(err) }
|
|
@@ -85174,6 +85322,15 @@ var NcLinkedStillShelf = class {
|
|
|
85174
85322
|
});
|
|
85175
85323
|
return stills;
|
|
85176
85324
|
}
|
|
85325
|
+
/**
|
|
85326
|
+
* While a wake of one of this owner's cameras is in flight: the instant it
|
|
85327
|
+
* gives up (its bound plus one poll). `undefined` otherwise — the dispatcher
|
|
85328
|
+
* then keeps its ordinary still-wait.
|
|
85329
|
+
*/
|
|
85330
|
+
pendingUntil(ownerId) {
|
|
85331
|
+
const ref = this.owners.get(ownerId);
|
|
85332
|
+
return ref === void 0 ? void 0 : this.pendingWakes.get(ref.setId);
|
|
85333
|
+
}
|
|
85177
85334
|
/** `undefined` = not an owner this shelf minted (or pruned); `[]` = nothing (yet). */
|
|
85178
85335
|
get(ownerId) {
|
|
85179
85336
|
const ref = this.owners.get(ownerId);
|
|
@@ -85195,20 +85352,37 @@ var NcLinkedStillShelf = class {
|
|
|
85195
85352
|
clear() {
|
|
85196
85353
|
this.sets.clear();
|
|
85197
85354
|
this.owners.clear();
|
|
85355
|
+
this.pendingWakes.clear();
|
|
85198
85356
|
}
|
|
85199
|
-
async run(setId, stills, atMs, startedAt) {
|
|
85200
|
-
const
|
|
85357
|
+
async run(setId, stills, atMs, startedAt, options) {
|
|
85358
|
+
const ctx = {
|
|
85359
|
+
setId,
|
|
85360
|
+
sensorId: stills.sensorId,
|
|
85361
|
+
startedAt,
|
|
85362
|
+
options
|
|
85363
|
+
};
|
|
85364
|
+
let results;
|
|
85365
|
+
try {
|
|
85366
|
+
results = await Promise.all(stills.cameraIds.map((id) => this.captureOne(id, ctx)));
|
|
85367
|
+
} finally {
|
|
85368
|
+
this.pendingWakes.delete(setId);
|
|
85369
|
+
}
|
|
85201
85370
|
const judged = await this.judgeFreshness(stills.sensorId, results, atMs);
|
|
85202
85371
|
for (const r of judged) this.logTile(stills.sensorId, r);
|
|
85203
85372
|
const landed = judged.filter(isLandedTile);
|
|
85204
85373
|
const composed = await this.compose(stills.sensorId, landed, atMs);
|
|
85205
85374
|
const undrawable = landed.length - composed.drawn;
|
|
85375
|
+
const woken = judged.filter((r) => r.woken === true).map((r) => r.cameraId);
|
|
85206
85376
|
this.deps.logger.info(composed.mosaic.length === 0 ? "sensor notification has no linked picture — it ships text-only" : "sensor notification pictures ready", {
|
|
85207
85377
|
tags: { deviceId: stills.sensorId },
|
|
85208
85378
|
meta: {
|
|
85209
85379
|
cameras: stills.cameraIds.length,
|
|
85210
85380
|
landed: composed.drawn,
|
|
85211
85381
|
...undrawable > 0 ? { undrawable } : {},
|
|
85382
|
+
...woken.length > 0 ? {
|
|
85383
|
+
woken,
|
|
85384
|
+
waitedMs: this.deps.now() - startedAt
|
|
85385
|
+
} : {},
|
|
85212
85386
|
dropped: Object.fromEntries(judged.filter((r) => r.outcome !== "landed").map((r) => [String(r.cameraId), r.outcome])),
|
|
85213
85387
|
tookMs: this.deps.now() - startedAt
|
|
85214
85388
|
}
|
|
@@ -85221,21 +85395,25 @@ var NcLinkedStillShelf = class {
|
|
|
85221
85395
|
mosaic: composed.mosaic
|
|
85222
85396
|
});
|
|
85223
85397
|
}
|
|
85224
|
-
async captureOne(cameraId,
|
|
85225
|
-
const took = () => this.deps.now() - startedAt;
|
|
85398
|
+
async captureOne(cameraId, ctx) {
|
|
85399
|
+
const took = () => this.deps.now() - ctx.startedAt;
|
|
85226
85400
|
if (this.deps.isOnline(cameraId) === false) return {
|
|
85227
85401
|
cameraId,
|
|
85228
85402
|
outcome: "excluded",
|
|
85229
85403
|
reason: "offline",
|
|
85230
85404
|
tookMs: took()
|
|
85231
85405
|
};
|
|
85232
|
-
const [verdict, capture] = await Promise.all([this.wrapperVerdict(cameraId), this.captureStill(cameraId)]);
|
|
85233
|
-
|
|
85406
|
+
const [verdict, capture] = await Promise.all([this.wrapperVerdict(cameraId), this.captureStill(cameraId, false, SENSOR_LINKED_CAPTURE_TIMEOUT_MS)]);
|
|
85407
|
+
const excluded = (reason) => ({
|
|
85234
85408
|
cameraId,
|
|
85235
85409
|
outcome: "excluded",
|
|
85236
|
-
reason
|
|
85410
|
+
reason,
|
|
85237
85411
|
tookMs: took()
|
|
85238
|
-
};
|
|
85412
|
+
});
|
|
85413
|
+
if (verdict.reason === "sleeping") return this.wakeOne(cameraId, ctx);
|
|
85414
|
+
if (verdict.reason === "waking" && ctx.options.wakeSleeping) return this.awaitWaking(cameraId, ctx);
|
|
85415
|
+
if (verdict.reason === "unreachable" && ctx.options.wakeSleeping) return excluded("wake-skipped:unreachable");
|
|
85416
|
+
if (verdict.reason !== null) return excluded(verdict.reason);
|
|
85239
85417
|
return {
|
|
85240
85418
|
cameraId,
|
|
85241
85419
|
...capture,
|
|
@@ -85243,9 +85421,84 @@ var NcLinkedStillShelf = class {
|
|
|
85243
85421
|
tookMs: took()
|
|
85244
85422
|
};
|
|
85245
85423
|
}
|
|
85246
|
-
|
|
85424
|
+
/** D998: one forced capture, by the rule's leave, at most once per gap per camera. */
|
|
85425
|
+
async wakeOne(cameraId, ctx) {
|
|
85426
|
+
const took = () => this.deps.now() - ctx.startedAt;
|
|
85427
|
+
const skipped = (reason) => ({
|
|
85428
|
+
cameraId,
|
|
85429
|
+
outcome: "excluded",
|
|
85430
|
+
reason,
|
|
85431
|
+
tookMs: took()
|
|
85432
|
+
});
|
|
85433
|
+
if (!ctx.options.wakeSleeping) return skipped("wake-skipped:policy");
|
|
85434
|
+
const last = this.lastWakeAt.get(cameraId);
|
|
85435
|
+
if (last !== void 0 && ctx.startedAt - last < NC_LINKED_WAKE_MIN_GAP_MS) return skipped("wake-skipped:recent-wake");
|
|
85436
|
+
this.lastWakeAt.set(cameraId, ctx.startedAt);
|
|
85437
|
+
this.markPending(ctx);
|
|
85438
|
+
this.deps.logger.info("linked battery camera woken for the sensor notification", {
|
|
85439
|
+
tags: { deviceId: cameraId },
|
|
85440
|
+
meta: {
|
|
85441
|
+
sensorId: ctx.sensorId,
|
|
85442
|
+
ruleIds: ctx.options.ruleIds ?? [],
|
|
85443
|
+
boundMs: NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS
|
|
85444
|
+
}
|
|
85445
|
+
});
|
|
85446
|
+
const capture = await this.captureStill(cameraId, true, NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS);
|
|
85447
|
+
return {
|
|
85448
|
+
cameraId,
|
|
85449
|
+
...this.asWakeResult(capture),
|
|
85450
|
+
woken: true,
|
|
85451
|
+
tookMs: took()
|
|
85452
|
+
};
|
|
85453
|
+
}
|
|
85454
|
+
/** A camera another wake already started: never forced, re-polled within the bound. */
|
|
85455
|
+
async awaitWaking(cameraId, ctx) {
|
|
85456
|
+
const took = () => this.deps.now() - ctx.startedAt;
|
|
85457
|
+
this.markPending(ctx);
|
|
85458
|
+
const polls = Math.floor(NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS / NC_LINKED_WAKE_POLL_MS);
|
|
85459
|
+
for (let i = 0; i < polls; i++) {
|
|
85460
|
+
await new Promise((resolve) => setTimeout(resolve, NC_LINKED_WAKE_POLL_MS));
|
|
85461
|
+
const verdict = await this.wrapperVerdict(cameraId);
|
|
85462
|
+
if (verdict.reason === "waking") continue;
|
|
85463
|
+
if (verdict.reason !== null) return {
|
|
85464
|
+
cameraId,
|
|
85465
|
+
outcome: "excluded",
|
|
85466
|
+
reason: verdict.reason,
|
|
85467
|
+
tookMs: took()
|
|
85468
|
+
};
|
|
85469
|
+
const capture = await this.captureStill(cameraId, false, SENSOR_LINKED_CAPTURE_TIMEOUT_MS);
|
|
85470
|
+
return {
|
|
85471
|
+
cameraId,
|
|
85472
|
+
...this.asWakeResult(capture),
|
|
85473
|
+
woken: true,
|
|
85474
|
+
tookMs: took()
|
|
85475
|
+
};
|
|
85476
|
+
}
|
|
85477
|
+
return {
|
|
85478
|
+
cameraId,
|
|
85479
|
+
outcome: "wake-timeout",
|
|
85480
|
+
woken: true,
|
|
85481
|
+
tookMs: took()
|
|
85482
|
+
};
|
|
85483
|
+
}
|
|
85484
|
+
markPending(ctx) {
|
|
85485
|
+
const until = ctx.startedAt + NC_LINKED_WAKE_CAPTURE_TIMEOUT_MS + NC_LINKED_WAKE_POLL_MS;
|
|
85486
|
+
this.pendingWakes.set(ctx.setId, Math.max(this.pendingWakes.get(ctx.setId) ?? 0, until));
|
|
85487
|
+
}
|
|
85488
|
+
/** A wake that brought nothing back names itself, not the generic `empty`. */
|
|
85489
|
+
asWakeResult(capture) {
|
|
85490
|
+
if (capture.outcome === "timeout") return {
|
|
85491
|
+
...capture,
|
|
85492
|
+
outcome: "wake-timeout"
|
|
85493
|
+
};
|
|
85494
|
+
return capture.outcome === "empty" || capture.outcome === "error" && capture.reason !== "undecodable" ? {
|
|
85495
|
+
...capture,
|
|
85496
|
+
outcome: "wake-refused"
|
|
85497
|
+
} : capture;
|
|
85498
|
+
}
|
|
85499
|
+
async captureStill(cameraId, force, timeoutMs) {
|
|
85247
85500
|
try {
|
|
85248
|
-
const shot = await withTimeout$2(this.deps.getSnapshot(cameraId),
|
|
85501
|
+
const shot = await withTimeout$2(force ? this.deps.getSnapshot(cameraId, { force: true }) : this.deps.getSnapshot(cameraId), timeoutMs, "snapshot cap");
|
|
85249
85502
|
if (shot === null || shot.base64.length === 0) return { outcome: "empty" };
|
|
85250
85503
|
const jpeg = await this.decodableStill(Buffer.from(shot.base64, "base64"));
|
|
85251
85504
|
if (jpeg === null) return {
|
|
@@ -86804,6 +87057,13 @@ var NC_RECORDED_FOOTAGE_WAIT_MS = 3e4;
|
|
|
86804
87057
|
var NC_STILL_WAIT_MS = 3e3;
|
|
86805
87058
|
var NC_STILL_WAIT_INTERVAL_MS = 500;
|
|
86806
87059
|
/**
|
|
87060
|
+
* D998 — the longest a sensor notification holds for a linked battery camera
|
|
87061
|
+
* that is being woken (`stillDeadline`). A `sent` row is final, so the picture
|
|
87062
|
+
* cannot follow the push: it is waited for here, bounded, or never attached.
|
|
87063
|
+
* Owners with no wake in flight keep {@link NC_STILL_WAIT_MS}.
|
|
87064
|
+
*/
|
|
87065
|
+
var NC_LINKED_WAKE_WAIT_MS = 15e3;
|
|
87066
|
+
/**
|
|
86807
87067
|
* How far a still's OWN instant may sit from the trigger and still count as
|
|
86808
87068
|
* being ABOUT the trigger, for a `delivery: 'immediate'` rule.
|
|
86809
87069
|
*
|
|
@@ -87772,6 +88032,36 @@ var NcDispatcher = class {
|
|
|
87772
88032
|
});
|
|
87773
88033
|
}
|
|
87774
88034
|
/**
|
|
88035
|
+
* The facts of a finished appliance cycle; unknown on every other row and on
|
|
88036
|
+
* any failure (a part that cannot be read is omitted, never a blocked send).
|
|
88037
|
+
*/
|
|
88038
|
+
async applianceCycleFacts(entry) {
|
|
88039
|
+
const subject = entry.payload.subject;
|
|
88040
|
+
const resolve = this.deps.resolveApplianceCycleFacts;
|
|
88041
|
+
const deviceId = subject.applianceCycle?.deviceId;
|
|
88042
|
+
if (resolve === void 0 || deviceId === void 0) return NC_UNKNOWN_CYCLE_FACTS;
|
|
88043
|
+
try {
|
|
88044
|
+
const facts = await resolve({
|
|
88045
|
+
deviceId,
|
|
88046
|
+
finishedAtMs: subject.timestamp
|
|
88047
|
+
});
|
|
88048
|
+
if (facts.durationMs === null || facts.energyKwh === null) this.deps.logger.debug("appliance cycle part omitted — unknown", {
|
|
88049
|
+
tags: { deviceId },
|
|
88050
|
+
meta: {
|
|
88051
|
+
duration: facts.durationMs === null ? "unknown" : "known",
|
|
88052
|
+
energy: facts.energyKwh === null ? "unknown" : "known"
|
|
88053
|
+
}
|
|
88054
|
+
});
|
|
88055
|
+
return facts;
|
|
88056
|
+
} catch (err) {
|
|
88057
|
+
this.deps.logger.debug("appliance cycle facts failed — parts omitted", {
|
|
88058
|
+
tags: { deviceId },
|
|
88059
|
+
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
88060
|
+
});
|
|
88061
|
+
return NC_UNKNOWN_CYCLE_FACTS;
|
|
88062
|
+
}
|
|
88063
|
+
}
|
|
88064
|
+
/**
|
|
87775
88065
|
* Builds the notification AND returns the artefact ids its media resolve
|
|
87776
88066
|
* indexed — see {@link withArtifactUrls}. A tuple rather than a field on
|
|
87777
88067
|
* `NcNotificationInput`: the ids are internal (outbox provenance), never
|
|
@@ -87783,7 +88073,8 @@ var NcDispatcher = class {
|
|
|
87783
88073
|
const deviceName = await notificationDeviceName(entry, this.deps.getDeviceName);
|
|
87784
88074
|
const alarmSource = systemEvent?.alarmSource;
|
|
87785
88075
|
const zoneLabels = systemEvent === void 0 ? await resolveZoneLabels(this.deps.getZoneNames, subject.deviceId, subject.zones) : alarmSource?.zones !== void 0 && alarmSource.zones.length > 0 ? await resolveZoneLabels(this.deps.getZoneNames, alarmSource.deviceId, alarmSource.zones) : [];
|
|
87786
|
-
const
|
|
88076
|
+
const cycleFacts = await this.applianceCycleFacts(entry);
|
|
88077
|
+
const vars = buildTemplateVars(this.texts, entry, deviceName, zoneLabels, void 0, cycleFacts);
|
|
87787
88078
|
this.warnDeprecatedVars(entry);
|
|
87788
88079
|
const systemCount = systemEvent?.textCount !== void 0 ? { count: systemEvent.textCount } : {};
|
|
87789
88080
|
const title = renderRowTitle(this.texts, entry, vars);
|
|
@@ -87989,7 +88280,15 @@ var NcDispatcher = class {
|
|
|
87989
88280
|
const firstLook = groupTiles !== null ? null : await this.resolveAttachment(entry, canStillGainMedia(entry) ? "trigger-only" : "any");
|
|
87990
88281
|
const footagePending = this.renderFootage(entry);
|
|
87991
88282
|
const mosaic = groupView !== void 0 && groupTiles !== null ? await this.groupedMosaic(entry, groupView, groupTiles) : null;
|
|
87992
|
-
|
|
88283
|
+
let waitedMs = 0;
|
|
88284
|
+
let still;
|
|
88285
|
+
if (mosaic !== null) still = mosaic.attachment;
|
|
88286
|
+
else if (firstLook !== null || entry.payload.media === "none") still = firstLook;
|
|
88287
|
+
else {
|
|
88288
|
+
const waited = await this.waitForStill(entry);
|
|
88289
|
+
still = waited.still;
|
|
88290
|
+
waitedMs = waited.waitedMs;
|
|
88291
|
+
}
|
|
87993
88292
|
const grouped = groupView !== void 0 && groupMembers !== null ? {
|
|
87994
88293
|
windowKey: groupView.key,
|
|
87995
88294
|
members: groupView.members.length,
|
|
@@ -88014,6 +88313,7 @@ var NcDispatcher = class {
|
|
|
88014
88313
|
recordKind: entry.recordKind,
|
|
88015
88314
|
recordId: entry.recordId,
|
|
88016
88315
|
policy: entry.payload.media,
|
|
88316
|
+
waitedMs,
|
|
88017
88317
|
...entry.payload.mediaImage !== void 0 ? { image: entry.payload.mediaImage } : {},
|
|
88018
88318
|
...memberTrackIds.length > 1 ? { memberTrackIds } : {},
|
|
88019
88319
|
owners: [...entry.payload.subject.eventId !== void 0 ? [`object:${entry.payload.subject.eventId}`] : [], ...entry.payload.subject.trackId !== void 0 ? [`track:${entry.payload.subject.trackId}`] : []]
|
|
@@ -88040,7 +88340,13 @@ var NcDispatcher = class {
|
|
|
88040
88340
|
const subject = entry.payload.subject;
|
|
88041
88341
|
const out = [];
|
|
88042
88342
|
for (const { ownerId, cameraId } of subject.extraStills ?? []) {
|
|
88043
|
-
|
|
88343
|
+
let file = await this.linkedStillFile(entry, ownerId, cameraId);
|
|
88344
|
+
for (let polls = 0; file === void 0 && polls < NC_LINKED_WAKE_WAIT_MS / NC_STILL_WAIT_INTERVAL_MS; polls += 1) {
|
|
88345
|
+
const deadline = this.deps.stillDeadline?.(ownerId);
|
|
88346
|
+
if (deadline === void 0 || this.now() >= deadline) break;
|
|
88347
|
+
await this.sleep(NC_STILL_WAIT_INTERVAL_MS);
|
|
88348
|
+
file = await this.linkedStillFile(entry, ownerId, cameraId);
|
|
88349
|
+
}
|
|
88044
88350
|
const bytes = file === void 0 ? null : decodeStillBytes(file.base64);
|
|
88045
88351
|
if (file === void 0 || bytes === null) {
|
|
88046
88352
|
this.deps.logger.info("linked camera picture missing at send — skipped", {
|
|
@@ -88527,11 +88833,19 @@ var NcDispatcher = class {
|
|
|
88527
88833
|
*/
|
|
88528
88834
|
async waitForStill(entry) {
|
|
88529
88835
|
const subject = entry.payload.subject;
|
|
88530
|
-
if (this.now() - subject.timestamp > NC_STILL_WAIT_MAX_AGE_MS) return
|
|
88531
|
-
|
|
88532
|
-
|
|
88533
|
-
|
|
88836
|
+
if (this.now() - subject.timestamp > NC_STILL_WAIT_MAX_AGE_MS) return {
|
|
88837
|
+
still: await this.resolveAttachment(entry, "any"),
|
|
88838
|
+
waitedMs: 0
|
|
88839
|
+
};
|
|
88840
|
+
if (subject.eventId === void 0 && subject.trackId === void 0) return {
|
|
88841
|
+
still: null,
|
|
88842
|
+
waitedMs: 0
|
|
88843
|
+
};
|
|
88844
|
+
const startedAt = this.now();
|
|
88845
|
+
let waitedMs = 0;
|
|
88846
|
+
for (let i = 0; waitedMs < this.stillWaitBoundMs(entry, startedAt); i += 1) {
|
|
88534
88847
|
await this.sleep(NC_STILL_WAIT_INTERVAL_MS);
|
|
88848
|
+
waitedMs += NC_STILL_WAIT_INTERVAL_MS;
|
|
88535
88849
|
const still = await this.resolveAttachment(entry, "trigger-only");
|
|
88536
88850
|
if (still !== null) {
|
|
88537
88851
|
this.deps.logger.info("the still landed during the bounded wait", {
|
|
@@ -88543,10 +88857,32 @@ var NcDispatcher = class {
|
|
|
88543
88857
|
kind: still.name
|
|
88544
88858
|
}
|
|
88545
88859
|
});
|
|
88546
|
-
return
|
|
88860
|
+
return {
|
|
88861
|
+
still,
|
|
88862
|
+
waitedMs
|
|
88863
|
+
};
|
|
88547
88864
|
}
|
|
88548
88865
|
}
|
|
88549
|
-
return
|
|
88866
|
+
return {
|
|
88867
|
+
still: await this.resolveAttachment(entry, "any"),
|
|
88868
|
+
waitedMs
|
|
88869
|
+
};
|
|
88870
|
+
}
|
|
88871
|
+
/**
|
|
88872
|
+
* How long this row's still poll may run: {@link NC_STILL_WAIT_MS}, or — while
|
|
88873
|
+
* the shelf says a linked camera of this row is being woken — until that
|
|
88874
|
+
* wake gives up, at most {@link NC_LINKED_WAKE_WAIT_MS} (D998).
|
|
88875
|
+
*/
|
|
88876
|
+
stillWaitBoundMs(entry, startedAt) {
|
|
88877
|
+
const subject = entry.payload.subject;
|
|
88878
|
+
const owners = [...subject.trackId !== void 0 ? [subject.trackId] : [], ...(subject.extraStills ?? []).map((extra) => extra.ownerId)];
|
|
88879
|
+
let deadline;
|
|
88880
|
+
for (const ownerId of owners) {
|
|
88881
|
+
const until = this.deps.stillDeadline?.(ownerId);
|
|
88882
|
+
if (until !== void 0 && (deadline === void 0 || until > deadline)) deadline = until;
|
|
88883
|
+
}
|
|
88884
|
+
if (deadline === void 0) return NC_STILL_WAIT_MS;
|
|
88885
|
+
return Math.max(NC_STILL_WAIT_MS, Math.min(NC_LINKED_WAKE_WAIT_MS, deadline - startedAt));
|
|
88550
88886
|
}
|
|
88551
88887
|
/**
|
|
88552
88888
|
* The grouped MOSAIC (D692 §6.2): one tile per member, at most
|
|
@@ -88694,8 +89030,8 @@ var NcDispatcher = class {
|
|
|
88694
89030
|
return ts !== void 0 && this.now() - ts <= NC_STILL_WAIT_MAX_AGE_MS;
|
|
88695
89031
|
});
|
|
88696
89032
|
await look("trigger-only", pollable());
|
|
88697
|
-
const
|
|
88698
|
-
for (let
|
|
89033
|
+
const startedAt = this.now();
|
|
89034
|
+
for (let waited = 0; waited < this.stillWaitBoundMs(entry, startedAt) && pollable().length > 0; waited += NC_STILL_WAIT_INTERVAL_MS) {
|
|
88699
89035
|
await this.sleep(NC_STILL_WAIT_INTERVAL_MS);
|
|
88700
89036
|
await look("trigger-only", pollable());
|
|
88701
89037
|
}
|
|
@@ -88950,7 +89286,7 @@ function systemEventParamsForTemplate(params) {
|
|
|
88950
89286
|
const { form: _form, attention: _attention, ...rest } = params;
|
|
88951
89287
|
return rest;
|
|
88952
89288
|
}
|
|
88953
|
-
function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone) {
|
|
89289
|
+
function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone, cycle) {
|
|
88954
89290
|
const subject = entry.payload.subject;
|
|
88955
89291
|
const occupancy = subject.occupancy;
|
|
88956
89292
|
const systemEvent = subject.systemEvent;
|
|
@@ -88986,6 +89322,7 @@ function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone) {
|
|
|
88986
89322
|
hitPercent: subject.audio?.hitPercent !== void 0 ? `${Math.round(subject.audio.hitPercent)}` : "",
|
|
88987
89323
|
db: subject.audio?.peakDbfs !== void 0 ? `${Math.round(subject.audio.peakDbfs)}` : "",
|
|
88988
89324
|
eventType: subject.eventType ?? "",
|
|
89325
|
+
...cycle !== void 0 ? ncApplianceCycleVars(texts, cycle) : NC_EMPTY_CYCLE_VARS,
|
|
88989
89326
|
rule: entry.payload.ruleName,
|
|
88990
89327
|
count: occupancy !== void 0 ? `${occupancy.count}` : group !== void 0 && group.members.length > 1 ? `${group.members.length}` : "",
|
|
88991
89328
|
capacity: occupancy !== void 0 ? `${occupancy.capacity}` : "",
|
|
@@ -89012,6 +89349,7 @@ function bodyKeyFor(entry) {
|
|
|
89012
89349
|
const subject = entry.payload.subject;
|
|
89013
89350
|
if (subject.systemEvent !== void 0) return subject.systemEvent.bodyKey ?? "";
|
|
89014
89351
|
if (subject.occupancy !== void 0) return "occupancy.body";
|
|
89352
|
+
if (subject.applianceCycle !== void 0) return "appliance.finished.body";
|
|
89015
89353
|
if (subject.packagePhase === "delivered" && subject.packagePossible === true) return "package.delivered.possible.body";
|
|
89016
89354
|
if (subject.packagePhase !== void 0) return `package.${subject.packagePhase}.body`;
|
|
89017
89355
|
return entry.recordKind === "track-end" ? "detection.body.trackEnd" : "detection.body";
|
|
@@ -89049,7 +89387,7 @@ function renderRowTitle(texts, entry, vars) {
|
|
|
89049
89387
|
const systemEvent = entry.payload.subject.systemEvent;
|
|
89050
89388
|
const intrusion = entry.payload.alarmIntrusion;
|
|
89051
89389
|
const count = systemEvent?.textCount;
|
|
89052
|
-
|
|
89390
|
+
const rendered = renderRowText(texts, {
|
|
89053
89391
|
template: intrusion !== void 0 ? void 0 : entry.payload.template?.title,
|
|
89054
89392
|
key: titleKeyFor(entry),
|
|
89055
89393
|
vars: intrusion !== void 0 ? {
|
|
@@ -89059,11 +89397,13 @@ function renderRowTitle(texts, entry, vars) {
|
|
|
89059
89397
|
...count !== void 0 ? { count } : {},
|
|
89060
89398
|
frozen: systemEvent?.title ?? entry.payload.ruleName
|
|
89061
89399
|
});
|
|
89400
|
+
return titleKeyFor(entry) === "appliance.finished.title" && entry.payload.template?.title === void 0 ? ncSentenceCaseBody(rendered) : rendered;
|
|
89062
89401
|
}
|
|
89063
89402
|
/** The default TITLE key — same shape, same pre-catalog reasoning. */
|
|
89064
89403
|
function titleKeyFor(entry) {
|
|
89065
89404
|
const systemEvent = entry.payload.subject.systemEvent;
|
|
89066
89405
|
if (systemEvent !== void 0) return systemEvent.titleKey ?? "";
|
|
89406
|
+
if (entry.payload.subject.applianceCycle !== void 0) return "appliance.finished.title";
|
|
89067
89407
|
if (entry.payload.alarmIntrusion !== void 0) return "alarm.intrusion.title";
|
|
89068
89408
|
const packagePhase = entry.payload.subject.packagePhase;
|
|
89069
89409
|
if (packagePhase === "delivered" && entry.payload.subject.packagePossible === true) return "package.delivered.possible.title";
|
|
@@ -102135,6 +102475,7 @@ function buildEntries(host, rule, subject, kind, matchedOn, userTargets = [], or
|
|
|
102135
102475
|
...subject.audioWindow.peakDbfs !== void 0 ? { peakDbfs: subject.audioWindow.peakDbfs } : {}
|
|
102136
102476
|
} } : {},
|
|
102137
102477
|
...subject.eventType !== void 0 ? { eventType: subject.eventType } : {},
|
|
102478
|
+
...applianceCycleOf(subject),
|
|
102138
102479
|
...subject.systemEvent !== void 0 ? { systemEvent: subject.systemEvent } : {}
|
|
102139
102480
|
}
|
|
102140
102481
|
};
|
|
@@ -104210,7 +104551,7 @@ function beginLinkedStills(host, request) {
|
|
|
104210
104551
|
if (rowCameraIds.length > 0 && rowShown.length === 0) return void 0;
|
|
104211
104552
|
const shown = host.unmutedCameras(cameraIds);
|
|
104212
104553
|
const involved = [sensorId, ...rowShown];
|
|
104213
|
-
|
|
104554
|
+
const wanting = host.rules.listEnabled("device-event").filter((rule) => {
|
|
104214
104555
|
if (ruleShipsNoStill(rule)) return false;
|
|
104215
104556
|
if (!deviceEventRuleMayFireOnKind(rule, sensorKind, sensorRaised)) return false;
|
|
104216
104557
|
const excluded = rule.conditions.devicesExclude;
|
|
@@ -104221,9 +104562,14 @@ function beginLinkedStills(host, request) {
|
|
|
104221
104562
|
})) return false;
|
|
104222
104563
|
const devices = rule.conditions.devices;
|
|
104223
104564
|
return devices === void 0 || devices.length === 0 || devices.some((id) => involved.includes(id));
|
|
104224
|
-
})
|
|
104565
|
+
});
|
|
104566
|
+
if (wanting.length === 0) return void 0;
|
|
104567
|
+
const wakeSleeping = wanting.some((rule) => rule.media?.wakeSleepingCamera !== false);
|
|
104225
104568
|
for (const cameraId of cameraIds) if (!shown.includes(cameraId)) host.reportLinkedCameraMuted(cameraId, sensorId);
|
|
104226
|
-
return shown.length > 0 ? shelf.captureSet(sensorId, shown, atMs
|
|
104569
|
+
return shown.length > 0 ? shelf.captureSet(sensorId, shown, atMs, {
|
|
104570
|
+
wakeSleeping,
|
|
104571
|
+
ruleIds: wanting.map((rule) => rule.id)
|
|
104572
|
+
}) : void 0;
|
|
104227
104573
|
}
|
|
104228
104574
|
/**
|
|
104229
104575
|
* A muted camera left out of a linked set — one INFO line per camera per
|
|
@@ -106946,6 +107292,7 @@ var NotificationCenter = class {
|
|
|
106946
107292
|
...deps.dispatcher,
|
|
106947
107293
|
logger: this.logger.child("dispatch"),
|
|
106948
107294
|
texts: this.texts,
|
|
107295
|
+
stillDeadline: (ownerId) => isLinkedStillId(ownerId) ? this.linkedStills?.pendingUntil(ownerId) : void 0,
|
|
106949
107296
|
getMediaForOwner: async (ownerKind, ownerId, eventScope) => {
|
|
106950
107297
|
const held = isSyntheticId(ownerId) ? this.syntheticMedia.get(ownerId) : void 0;
|
|
106951
107298
|
if (held !== void 0) return held.files;
|
|
@@ -109529,7 +109876,10 @@ var BuildNotificationCenter = class extends BuildNotificationCenterBase {
|
|
|
109529
109876
|
},
|
|
109530
109877
|
readAlerts: () => api.alerts.list.query({ limit: 5e3 }),
|
|
109531
109878
|
emitBusEvent: (event) => this.ctx.eventBus.emit(event),
|
|
109532
|
-
getSnapshot: (deviceId) => api.snapshot.getSnapshot.query(
|
|
109879
|
+
getSnapshot: (deviceId, opts) => api.snapshot.getSnapshot.query(opts?.force === true ? {
|
|
109880
|
+
deviceId,
|
|
109881
|
+
force: true
|
|
109882
|
+
} : { deviceId }),
|
|
109533
109883
|
recognitionOutlook: ({ deviceId, trackId, className, labelKind, now }) => recognitionOutlook({
|
|
109534
109884
|
className,
|
|
109535
109885
|
...labelKind !== void 0 ? { labelKind } : {},
|
|
@@ -109872,6 +110222,7 @@ var BuildNotificationCenter = class extends BuildNotificationCenterBase {
|
|
|
109872
110222
|
}));
|
|
109873
110223
|
},
|
|
109874
110224
|
getDeviceName,
|
|
110225
|
+
resolveApplianceCycleFacts: this.deps.resolveApplianceCycleFacts,
|
|
109875
110226
|
getDeviceLocation,
|
|
109876
110227
|
buildActions: (input) => this.notificationCenter?.mintButtons(input) ?? Promise.resolve([])
|
|
109877
110228
|
},
|
|
@@ -123743,7 +124094,16 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
123743
124094
|
buildTimelapsePorts: (api, stores) => this.buildTimelapsePorts(api, stores),
|
|
123744
124095
|
buildSummaryPorts: (api, stores) => this.buildSummaryPorts(api, stores),
|
|
123745
124096
|
wireAlarmPanel: (center) => this.wireAlarmPanel(center),
|
|
123746
|
-
serveNcActionPlane: (center) => this.serveNcActionPlane(center)
|
|
124097
|
+
serveNcActionPlane: (center) => this.serveNcActionPlane(center),
|
|
124098
|
+
resolveApplianceCycleFacts: applianceCycleFactsFromRuns({
|
|
124099
|
+
newestRun: async (deviceId) => {
|
|
124100
|
+
return (await this.ctx.api.deviceRuns.listRuns.query({
|
|
124101
|
+
deviceId,
|
|
124102
|
+
limit: 1
|
|
124103
|
+
})).runs[0] ?? null;
|
|
124104
|
+
},
|
|
124105
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
124106
|
+
})
|
|
123747
124107
|
});
|
|
123748
124108
|
return this.notificationCenterBootInstance;
|
|
123749
124109
|
}
|