@camstack/addon-post-analysis 1.2.319 → 1.2.320
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/{clip-model-registry-DSqobJfx.mjs → clip-model-registry-C-IEAIQQ.mjs} +223 -46
- package/dist/{clip-model-registry-BjYpZuuI.js → clip-model-registry-C_aKxHpy.js} +252 -45
- 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-CKHzDA_B.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-D553qWb_.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-7e_3hsiC.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-C1V_UEyk.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-DDDjJDA6.mjs → hostInit-ByDyL2zi.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +287 -66
- package/dist/pipeline-analytics/index.mjs +287 -66
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bz37odzX.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-B_KS96RA.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as NC_ALARM_SYSTEM_EVENT_KINDS, $n as
|
|
1
|
+
import { $ as NC_ALARM_SYSTEM_EVENT_KINDS, $n as isVectorIndexDimConflict, $r as boolean, $t as SCENE_DEFAULT_UNCOVERED_POLICY, A as EMBEDDING_REQUIREMENTS_FAILED, An as describeSystemEventDeliveryProblem, Ar as templateCarriesSummary, At as NcScheduleSchema, B as ListTrackRelationsInputSchema, Bn as failureContributionCapability, Br as BaseAddon, Bt as OPS_LOG_DEFAULT_LIMIT, C as DEFAULT_EVENT_COLOR, Cn as assertTimelapseCadences, Cr as storageOccupancyCapability, Ct as NcConditionDescriptorSchema, D as DeclaredDevices, Dn as consumableLowPercentOf, Dr as systemEventFilterApplies, Dt as NcRuleSchema, E as DETECTION_PIPELINE_CAP_NAME, En as buildEventKindDescriptor, Er as systemEventFamilyProblems, Et as NcRulePatchSchema, F as EXPORT_DENSE_MAX_RANGES, Fr as canonicalHash, Ft as NcSystemEventKindSchema, G as MAX_BIRTH_LATENCY_PROXY_MS, Gn as isDetectionMacroClass, Gr as hydrateSchema, Gt as RebuildObjectEmbeddingsRefusalSchema, H as LockStateSchema, Hn as gifFromMp4Args, Hr as createEvent, I as FIRST_LEVEL_MACRO_CLASSES, Ir as evaluateSensorEdge, It as NcTaxonomySchema, J as MOTION_CLOSE_AFTER_MS, Jn as isMediaOwnerType, Jt as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, K as MAX_TRACK_PURITIES, Kn as isEventOwnerType, Kr as isDeviceScopedCap, Kt as RetrainStatusSchema, L as FULL_IMAGE_BBOX, Ln as encodeVectorBase64, Lr as isSourceCap, Lt as NcTemplatePreviewInputSchema, M as EVENT_DENSITY_BATCH_MAX, Mr as vectorDimFromBase64, Mt as NcSnoozeSchema, N as EVENT_KIND_BY_CAP, Nr as zoneAnalyticsCapability, Nt as NcSnoozeSuppressedSchema, O as DetectionSourceSchema, On as cosineSimilarity$1, Or as systemEventSummaryScheduleOf, Ot as NcRuleTargetSchema, P as EVENT_OWNER_TYPES, Pn as embeddingRefusalOf, Pr as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, Pt as NcStateSummarySectionIdSchema, Q as NC_ALARM_DELAY_MAX_SEC, Qn as isSystemEventSummaryRule, Qr as array, Qt as SCENE_DEFAULT_QUIET_SECONDS, R as FailureCounters, Rn as evictionPolicyOfLocation, Rr as DeviceType, Rt as NcTemplatePreviewSchema, S as CoverStateSchema, Sn as applySecureOnArmEdit, Sr as servedTemplateVars, St as NcAlarmSettingsPatchSchema, T as DETECTION_MACRO_CLASSES, Tn as audioModeOf, Tr as systemEventDeliveryProblems, Tt as NcRuleInputSchema, U as MAX_ARCHIVED_DEBUG_NOTES, Un as isAlarmControllableCap, Ur as customAction, Ut as RECORDING_EXPORT_MAX_READ_BYTES, V as ListTrackRelationsResultSchema, Vn as gifDeriveSpeed, Vr as CamProfileSchema, Vt as OpsLogEntrySchema, W as MAX_BIRTH_DECISION_RECORDS, Wn as isAudioClassName, Wr as defineCustomActions, Wt as RECORDING_SOURCE_CAMSTACK_ADDON, X as MotionTriggeredBySchema, Xn as isScheduleActive, Xr as ZodObject, Xt as SCENE_DEFAULT_CHECK_INTERVAL_SEC, Y as MediaFileKindEnum, Yn as isRetiredClearKey, Yr as sleep$1, Yt as SCENE_DEFAULT_ANCHOR_THRESHOLD, Z as NC_ALARM_DELAY_FIELDS, Zn as isSystemDelivery, Zr as _enum, Zt as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, _ as BaseDevice, _n as alarmDeviceSecureOnArm, _r as ruleGroupingApplies, _t as NC_TAXONOMY, a as CLIP_EMBEDDING_STEP_ID, ai as partialRecord, an as SetTrackRelationInputSchema, at as NC_CLIP_RETENTION_MAX_SEC, b as ClearTrackRelationInputSchema, bn as applyModeDelaysEdits, br as secureActuationFor, bt as NcAlarmSensorsInputSchema, c as resolveClusterModelPin, ci as string, cn as TimelapseRuleInputSchema, cr as readDeviceStateFrom, ct as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, d as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, di as union, dn as TrackPuritySchema, dr as resolveClipSearchMinScore, dt as NC_GROUPING_MAX_SEC, ei as discriminatedUnion, en as SCENE_DIVERGED, er as kebabToCamel, et as NC_ALARM_TRIGGERED_MAX_SEC, f as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, fi as unknown, fn as TrackRelationKindSchema, fr as resolveLocationMode, ft as NC_GROUPING_MIN_SEC, g as BIRTH_DECISION_DEFAULT_LIMIT, gn as addonWidgetsSourceCapability, gr as ruleDeviceCompatCapQueries, gt as NC_TANK_SYSTEM_EVENT_KINDS, h as ArchivedDebugNoteSchema, hn as TrackSourceSchema, hr as ruleBelongsToAlarm$1, ht as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, ii as object, in as SetTrackPurityResultSchema, ir as occupancyScope, it as NC_CLIP_PRE_ROLL_DEFAULT_SEC, j as EMBEDDING_REQUIREMENTS_UNAVAILABLE, jn as describeSystemEventFamilyProblem, jr as templateVarsFor, jt as NcSnoozeInputSchema, k as EMBEDDING_MODEL_FAILED, kn as deriveRecordingMode, kr as systemEventSummarySplitOf, kt as NcRuleUpdateInputSchema, l as APPEARANCE_BIN_COUNT, li as templateLiteral, ln as TimelapseRulePatchSchema, lr as readMotionTriggeredBy, lt as NC_DEFAULT_SNOOZE_MINUTES, m as AlarmArmModeSchema, mn as TrackSideSchema, mt as NC_SNOOZE_MAX_MINUTES, ni as looseObject, nn as SceneMonitorSchema, nr as memoizePinnedFfmpeg, nt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, o as FACE_EMBEDDING_STEP_ID, oi as record, on as TIMELAPSE_DENSE_FLOOR_SEC, or as pipelineAnalyticsCapability, ot as NC_CONDITION_CATALOG, p as AUDIO_MACRO_LABELS, pi as EventCategory, pn as TrackRelationSchema, pr as resolveModeDelays, pt as NC_SENSOR_TRANSITION_KINDS, q as MAX_TRACK_RELATIONS, qn as isKnownTemplateVar, qr as nodePin, qt as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, ri as number, rn as SetTrackPurityInputSchema, rr as notificationRulesCapability, rt as NC_CLIP_POST_ROLL_DEFAULT_SEC, s as readClusterModelPinStrict, si as strictObject, sn as TRACK_RELATIONS_DEFAULT_LIMIT, sr as plateGalleryCapability, st as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, t as BUILTIN_CLIP_MODELS, ti as literal, tn as SCENE_RESET_RECAPTURES, tr as mayWriteToLocation, tt as NC_AUDIO_CONFIRM_HITS_DEFAULT, u as APPEARANCE_BLOCKS, ui as tuple, un as TimelapseRuleSchema, ur as readTimelapseGeneratedAt, ut as NC_GROUPING_DEFAULT_SEC, v as BirthDecisionRecordSchema, vn as alarmPanelCapability, vr as ruleKindOf, vt as NC_TEMPLATE_VARS, w as DEFAULT_TIMELAPSE_PREVIEW_TEXT, wn as audioMetricsCapability, wr as subKindsOf, wt as NcConditionsSchema, x as ClearTrackRelationResultSchema, xn as applyNonBlockingEdit, xr as sensorRaisedOf, xt as NcAlarmSensorsSchema, y as COCO_TO_MACRO, yn as applyBlockingEdit, yr as sceneMonitorCapability, yt as NcAlarmConfigSchema, z as LabelAttributionSchema, zn as faceGalleryCapability, zr as errMsg, zt as NcTemplateVarDescriptorSchema } from "../clip-model-registry-C-IEAIQQ.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs$1 from "node:fs";
|
|
4
4
|
import { createWriteStream, promises } from "node:fs";
|
|
@@ -597,7 +597,19 @@ var ARM_ANYWAY_TTL_MS = 5 * 6e4;
|
|
|
597
597
|
var NcAlarmOpenDeviceSchema = object({
|
|
598
598
|
deviceId: number().int(),
|
|
599
599
|
name: string(),
|
|
600
|
-
state: string()
|
|
600
|
+
state: string(),
|
|
601
|
+
/**
|
|
602
|
+
* Cover / lock / switch — default false so an older bridge answer still
|
|
603
|
+
* parses as a contact-style opening.
|
|
604
|
+
*/
|
|
605
|
+
controllable: boolean().default(false),
|
|
606
|
+
/** Opening cap that produced the reading; used to actuate secure-on-arm. */
|
|
607
|
+
cap: _enum([
|
|
608
|
+
"contact",
|
|
609
|
+
"cover",
|
|
610
|
+
"lock-control",
|
|
611
|
+
"switch"
|
|
612
|
+
]).optional()
|
|
601
613
|
}).readonly();
|
|
602
614
|
/** Why an Arm anyway was not honoured — see `NcAlarmPanelDevice.armAnyway`. */
|
|
603
615
|
var NcAlarmArmAnywayRejectionSchema = _enum([
|
|
@@ -662,23 +674,22 @@ function alarmCoveredDevices(rules, panelDeviceId, mode) {
|
|
|
662
674
|
/**
|
|
663
675
|
* Refuse or arm — the whole decision, as one partition of the open devices.
|
|
664
676
|
*
|
|
665
|
-
* A device may be open at arm time
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
* confirming: they were never shown it, and excluding it would arm the alarm
|
|
670
|
-
* around an opening nobody agreed to.
|
|
677
|
+
* A device may be open at arm time when:
|
|
678
|
+
* - the mode TOLERATES it (`nonBlocking` for contacts),
|
|
679
|
+
* - it is controllable and NOT on the mode's `blocking` list (default),
|
|
680
|
+
* - or the operator confirmed it with Arm anyway (`acknowledged`).
|
|
671
681
|
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
* Arm anyway, whose lifecycle (one-shot, stale, expired) the panel owns.
|
|
682
|
+
* Anything else open refuses — including a device that opened AFTER the refusal
|
|
683
|
+
* the operator is confirming.
|
|
675
684
|
*
|
|
676
685
|
* Excluded is EVERY open device — tolerated and acknowledged alike — and the
|
|
677
686
|
* exclusion is two-phase (`alarm-exclusions.ts`): each one is watched again
|
|
678
687
|
* once it has closed and opened.
|
|
679
688
|
*/
|
|
680
689
|
function decideArm(input) {
|
|
690
|
+
const forceBlock = new Set(input.blocking ?? []);
|
|
681
691
|
const tolerated = new Set([...input.nonBlocking, ...input.acknowledged ?? []]);
|
|
692
|
+
for (const d of input.open) if (d.controllable && !forceBlock.has(d.deviceId)) tolerated.add(d.deviceId);
|
|
682
693
|
const blocking = input.open.filter((d) => !tolerated.has(d.deviceId));
|
|
683
694
|
if (blocking.length > 0) return {
|
|
684
695
|
kind: "refused",
|
|
@@ -1066,39 +1077,24 @@ var NcActionPlane = class {
|
|
|
1066
1077
|
* and never open):
|
|
1067
1078
|
*
|
|
1068
1079
|
* - `not-opening` — no opening slice at all: a camera named by an intrusion
|
|
1069
|
-
* rule
|
|
1080
|
+
* rule. It takes no part in the arm decision.
|
|
1070
1081
|
* - `unknown` — an opening cap's slice IS there, but its field is missing or
|
|
1071
1082
|
* is not a word that cap defines, or the slice is a provider's PLACEHOLDER
|
|
1072
|
-
* (`lastChangedAt === 0
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1076
|
-
* saw. It never blocks and is never armed as secure on a guess — and a
|
|
1077
|
-
* placeholder is never taken for a state, so neither the reconcile tick,
|
|
1078
|
-
* the arm check nor an exclusion lift acts on one.
|
|
1079
|
-
* - `reading` — open or secure, with the state word a person will read.
|
|
1080
|
-
* ANY non-zero `lastChangedAt` is a reading, however old — including `1`,
|
|
1081
|
-
* the stamp a provider writes on a value it REPLAYED after a respawn with
|
|
1082
|
-
* no upstream change time (Homematic `HM_SEEDED_CHANGED_AT`): the value is
|
|
1083
|
-
* known, only its change time is not. The transition gate
|
|
1084
|
-
* (`sensor-transition-gate.ts`, "A placeholder slice is not a state") reads
|
|
1085
|
-
* the same stamp as "not a fresh event"; `0` alone means "not read yet".
|
|
1083
|
+
* (`lastChangedAt === 0`). It never blocks and is never armed as secure on a
|
|
1084
|
+
* guess.
|
|
1085
|
+
* - `reading` — open or secure, with the state word a person will read and the
|
|
1086
|
+
* cap that produced it (so secure-on-arm knows what to actuate).
|
|
1086
1087
|
*
|
|
1087
1088
|
* A read that FAILED never reaches {@link alarmOpeningFrom}: the caller leaves
|
|
1088
1089
|
* that id out of its answer (see {@link readAlarmOpenings}).
|
|
1089
1090
|
*
|
|
1090
1091
|
* Anything short of fully secure is open: a cover stopped half-way, a lock that
|
|
1091
|
-
* jammed, a cover still closing when the arm is decided.
|
|
1092
|
+
* jammed, a cover still closing when the arm is decided, a switch that is on.
|
|
1092
1093
|
*
|
|
1093
1094
|
* PRECEDENCE, when one device carries more than one opening slice: `contact`
|
|
1094
|
-
* first, then `cover`, then `lock-control`. The contact is the
|
|
1095
|
-
* about the opening — a reed switch on the frame says the window
|
|
1096
|
-
* when the motor's last reported word says `closed`.
|
|
1097
|
-
* read falls through to the next; only when none of them reads is the device
|
|
1098
|
-
* `unknown`, naming the first unreadable cap.
|
|
1099
|
-
*
|
|
1100
|
-
* The vocabulary of each word is its cap's own schema (`CoverStateSchema`,
|
|
1101
|
-
* `LockStateSchema`) — a word the cap does not define is not guessed at.
|
|
1095
|
+
* first, then `cover`, then `lock-control`, then `switch`. The contact is the
|
|
1096
|
+
* physical truth about the opening — a reed switch on the frame says the window
|
|
1097
|
+
* is open even when the motor's last reported word says `closed`.
|
|
1102
1098
|
*/
|
|
1103
1099
|
/** The one state word, per cap, that counts as secure. Everything else is open. */
|
|
1104
1100
|
var COVER_SECURE = "closed";
|
|
@@ -1117,11 +1113,12 @@ function fieldOf(slice, field) {
|
|
|
1117
1113
|
function isPlaceholder(slice) {
|
|
1118
1114
|
return fieldOf(slice, "lastChangedAt") === 0;
|
|
1119
1115
|
}
|
|
1120
|
-
function reading(word, secure) {
|
|
1116
|
+
function reading(word, secure, cap) {
|
|
1121
1117
|
return {
|
|
1122
1118
|
kind: "reading",
|
|
1123
1119
|
reading: word === secure ? "secure" : "open",
|
|
1124
|
-
state: word
|
|
1120
|
+
state: word,
|
|
1121
|
+
cap
|
|
1125
1122
|
};
|
|
1126
1123
|
}
|
|
1127
1124
|
function readContact(runtime) {
|
|
@@ -1141,11 +1138,13 @@ function readContact(runtime) {
|
|
|
1141
1138
|
return raw ? {
|
|
1142
1139
|
kind: "reading",
|
|
1143
1140
|
reading: "open",
|
|
1144
|
-
state: "open"
|
|
1141
|
+
state: "open",
|
|
1142
|
+
cap: "contact"
|
|
1145
1143
|
} : {
|
|
1146
1144
|
kind: "reading",
|
|
1147
1145
|
reading: "secure",
|
|
1148
|
-
state: "closed"
|
|
1146
|
+
state: "closed",
|
|
1147
|
+
cap: "contact"
|
|
1149
1148
|
};
|
|
1150
1149
|
}
|
|
1151
1150
|
function readCover(runtime) {
|
|
@@ -1158,7 +1157,7 @@ function readCover(runtime) {
|
|
|
1158
1157
|
};
|
|
1159
1158
|
const raw = fieldOf(slice, "state");
|
|
1160
1159
|
const parsed = CoverStateSchema.safeParse(raw);
|
|
1161
|
-
return parsed.success ? reading(parsed.data, COVER_SECURE) : {
|
|
1160
|
+
return parsed.success ? reading(parsed.data, COVER_SECURE, "cover") : {
|
|
1162
1161
|
kind: "unknown",
|
|
1163
1162
|
cap: "cover",
|
|
1164
1163
|
raw
|
|
@@ -1174,19 +1173,46 @@ function readLock(runtime) {
|
|
|
1174
1173
|
};
|
|
1175
1174
|
const raw = fieldOf(slice, "state");
|
|
1176
1175
|
const parsed = LockStateSchema.safeParse(raw);
|
|
1177
|
-
return parsed.success ? reading(parsed.data, LOCK_SECURE) : {
|
|
1176
|
+
return parsed.success ? reading(parsed.data, LOCK_SECURE, "lock-control") : {
|
|
1178
1177
|
kind: "unknown",
|
|
1179
1178
|
cap: "lock-control",
|
|
1180
1179
|
raw
|
|
1181
1180
|
};
|
|
1182
1181
|
}
|
|
1182
|
+
function readSwitch(runtime) {
|
|
1183
|
+
const slice = sliceOf(runtime, "switch");
|
|
1184
|
+
if (slice === void 0) return { kind: "absent" };
|
|
1185
|
+
if (isPlaceholder(slice)) return {
|
|
1186
|
+
kind: "unknown",
|
|
1187
|
+
cap: "switch",
|
|
1188
|
+
raw: slice
|
|
1189
|
+
};
|
|
1190
|
+
const raw = fieldOf(slice, "on");
|
|
1191
|
+
if (typeof raw !== "boolean") return {
|
|
1192
|
+
kind: "unknown",
|
|
1193
|
+
cap: "switch",
|
|
1194
|
+
raw
|
|
1195
|
+
};
|
|
1196
|
+
return raw ? {
|
|
1197
|
+
kind: "reading",
|
|
1198
|
+
reading: "open",
|
|
1199
|
+
state: "on",
|
|
1200
|
+
cap: "switch"
|
|
1201
|
+
} : {
|
|
1202
|
+
kind: "reading",
|
|
1203
|
+
reading: "secure",
|
|
1204
|
+
state: "off",
|
|
1205
|
+
cap: "switch"
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1183
1208
|
/** D630's table over one device's runtime slices — see the header for the three answers. */
|
|
1184
1209
|
function alarmOpeningFrom(runtime) {
|
|
1185
1210
|
let firstUnknown = null;
|
|
1186
1211
|
for (const read of [
|
|
1187
1212
|
readContact(runtime),
|
|
1188
1213
|
readCover(runtime),
|
|
1189
|
-
readLock(runtime)
|
|
1214
|
+
readLock(runtime),
|
|
1215
|
+
readSwitch(runtime)
|
|
1190
1216
|
]) {
|
|
1191
1217
|
if (read.kind === "reading") return read;
|
|
1192
1218
|
if (read.kind === "unknown" && firstUnknown === null) firstUnknown = read;
|
|
@@ -1201,13 +1227,14 @@ function alarmOpeningFrom(runtime) {
|
|
|
1201
1227
|
var OPENING_CAP_BY_EVENT_KIND = {
|
|
1202
1228
|
contact: "contact",
|
|
1203
1229
|
cover: "cover",
|
|
1204
|
-
lock: "lock-control"
|
|
1230
|
+
lock: "lock-control",
|
|
1231
|
+
switch: "switch"
|
|
1205
1232
|
};
|
|
1206
1233
|
/**
|
|
1207
1234
|
* The same table, read off one sensor-event row: its `value` IS the slice of
|
|
1208
1235
|
* the cap its `kind` names, so the event path and the reconcile read answer in
|
|
1209
1236
|
* one vocabulary — a cover is secure only when `closed`, a lock only when
|
|
1210
|
-
* `locked`, whichever path saw it.
|
|
1237
|
+
* `locked`, a switch only when off, whichever path saw it.
|
|
1211
1238
|
*/
|
|
1212
1239
|
function alarmOpeningFromSensorEvent(kind, value) {
|
|
1213
1240
|
const cap = OPENING_CAP_BY_EVENT_KIND[kind];
|
|
@@ -1228,7 +1255,9 @@ function classifyCoveredOpening(opening) {
|
|
|
1228
1255
|
if (opening.kind === "not-opening" || opening.reading !== "open") return { kind: "skip" };
|
|
1229
1256
|
return {
|
|
1230
1257
|
kind: "open",
|
|
1231
|
-
state: opening.state
|
|
1258
|
+
state: opening.state,
|
|
1259
|
+
controllable: isAlarmControllableCap(opening.cap),
|
|
1260
|
+
cap: opening.cap
|
|
1232
1261
|
};
|
|
1233
1262
|
}
|
|
1234
1263
|
/**
|
|
@@ -1885,6 +1914,22 @@ var ncAlarmPanelSchema = object({
|
|
|
1885
1914
|
deviceIds: array(number().int())
|
|
1886
1915
|
})).default([]),
|
|
1887
1916
|
/**
|
|
1917
|
+
* Controllable openings that DO block when open (opt-in). Loose + guarded like
|
|
1918
|
+
* {@link nonBlocking}.
|
|
1919
|
+
*/
|
|
1920
|
+
blocking: array(object({
|
|
1921
|
+
mode: string(),
|
|
1922
|
+
deviceIds: array(number().int())
|
|
1923
|
+
})).default([]),
|
|
1924
|
+
/**
|
|
1925
|
+
* Controllable openings that must NOT secure on arm (opt-out). Loose + guarded
|
|
1926
|
+
* like {@link nonBlocking}.
|
|
1927
|
+
*/
|
|
1928
|
+
secureOnArmOff: array(object({
|
|
1929
|
+
mode: string(),
|
|
1930
|
+
deviceIds: array(number().int())
|
|
1931
|
+
})).default([]),
|
|
1932
|
+
/**
|
|
1888
1933
|
* Per arm mode, the delays that override the global ones (D697). Loose on purpose — `mode` is
|
|
1889
1934
|
* a string and the numbers are unbounded here — and read back through
|
|
1890
1935
|
* {@link modeDelaysFromPersisted}, never a cast: an entry this release cannot trust is dropped
|
|
@@ -1903,7 +1948,7 @@ var ncAlarmPanelSchema = object({
|
|
|
1903
1948
|
* per mode kept — the same "at most one list per mode" the settings schema
|
|
1904
1949
|
* enforces at the boundary. A type guard (`safeParse`), never a cast.
|
|
1905
1950
|
*/
|
|
1906
|
-
function
|
|
1951
|
+
function modeDeviceListFromPersisted(raw) {
|
|
1907
1952
|
const seen = /* @__PURE__ */ new Set();
|
|
1908
1953
|
const lists = [];
|
|
1909
1954
|
for (const entry of raw) {
|
|
@@ -2008,7 +2053,9 @@ var NcAlarmPanelDevice = class extends BaseDevice {
|
|
|
2008
2053
|
...this.readDelays(),
|
|
2009
2054
|
announceArm: this.config.get("announceArm"),
|
|
2010
2055
|
announceTargets: [...this.config.get("announceTargets")],
|
|
2011
|
-
nonBlocking:
|
|
2056
|
+
nonBlocking: modeDeviceListFromPersisted(this.config.get("nonBlocking")),
|
|
2057
|
+
blocking: modeDeviceListFromPersisted(this.config.get("blocking")),
|
|
2058
|
+
secureOnArmOff: modeDeviceListFromPersisted(this.config.get("secureOnArmOff")),
|
|
2012
2059
|
modeDelays: modeDelaysFromPersisted(this.config.get("modeDelays")).entries
|
|
2013
2060
|
};
|
|
2014
2061
|
}
|
|
@@ -2035,30 +2082,73 @@ var NcAlarmPanelDevice = class extends BaseDevice {
|
|
|
2035
2082
|
async applySettings(patch) {
|
|
2036
2083
|
const edits = patch.modeDelays ?? [];
|
|
2037
2084
|
const membership = patch.nonBlockingEdit;
|
|
2085
|
+
const blockingEdit = patch.blockingEdit;
|
|
2086
|
+
const secureEdit = patch.secureOnArmEdit;
|
|
2038
2087
|
for (const edit of edits) this.refuseUnofferedMode(edit.mode);
|
|
2039
2088
|
if (membership !== void 0) {
|
|
2040
2089
|
this.refuseUnofferedMode(membership.mode, membership.deviceId);
|
|
2041
|
-
const verdict = applyNonBlockingEdit(patch.nonBlocking !== void 0 ? patch.nonBlocking :
|
|
2090
|
+
const verdict = applyNonBlockingEdit(patch.nonBlocking !== void 0 ? patch.nonBlocking : modeDeviceListFromPersisted(this.config.get("nonBlocking")), membership);
|
|
2042
2091
|
if (verdict.kind === "refused") {
|
|
2043
2092
|
this.ctx.logger.info("alarm settings refused", {
|
|
2044
2093
|
tags: { deviceId: membership.deviceId },
|
|
2045
2094
|
meta: {
|
|
2046
2095
|
panelId: this.id,
|
|
2047
2096
|
reason: "list-full",
|
|
2048
|
-
mode: verdict.mode
|
|
2097
|
+
mode: verdict.mode,
|
|
2098
|
+
list: "nonBlocking"
|
|
2049
2099
|
}
|
|
2050
2100
|
});
|
|
2051
2101
|
throw new Error(`the ${verdict.mode} non-blocking list already holds ${verdict.max} devices — remove one first`);
|
|
2052
2102
|
}
|
|
2053
2103
|
}
|
|
2104
|
+
if (blockingEdit !== void 0) {
|
|
2105
|
+
this.refuseUnofferedMode(blockingEdit.mode, blockingEdit.deviceId);
|
|
2106
|
+
const verdict = applyBlockingEdit(patch.blocking !== void 0 ? patch.blocking : modeDeviceListFromPersisted(this.config.get("blocking")), blockingEdit);
|
|
2107
|
+
if (verdict.kind === "refused") {
|
|
2108
|
+
this.ctx.logger.info("alarm settings refused", {
|
|
2109
|
+
tags: { deviceId: blockingEdit.deviceId },
|
|
2110
|
+
meta: {
|
|
2111
|
+
panelId: this.id,
|
|
2112
|
+
reason: "list-full",
|
|
2113
|
+
mode: verdict.mode,
|
|
2114
|
+
list: "blocking"
|
|
2115
|
+
}
|
|
2116
|
+
});
|
|
2117
|
+
throw new Error(`the ${verdict.mode} blocking list already holds ${verdict.max} devices — remove one first`);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
if (secureEdit !== void 0) {
|
|
2121
|
+
this.refuseUnofferedMode(secureEdit.mode, secureEdit.deviceId);
|
|
2122
|
+
const verdict = applySecureOnArmEdit(patch.secureOnArmOff !== void 0 ? patch.secureOnArmOff : modeDeviceListFromPersisted(this.config.get("secureOnArmOff")), secureEdit);
|
|
2123
|
+
if (verdict.kind === "refused") {
|
|
2124
|
+
this.ctx.logger.info("alarm settings refused", {
|
|
2125
|
+
tags: { deviceId: secureEdit.deviceId },
|
|
2126
|
+
meta: {
|
|
2127
|
+
panelId: this.id,
|
|
2128
|
+
reason: "list-full",
|
|
2129
|
+
mode: verdict.mode,
|
|
2130
|
+
list: "secureOnArmOff"
|
|
2131
|
+
}
|
|
2132
|
+
});
|
|
2133
|
+
throw new Error(`the ${verdict.mode} secure-on-arm-off list already holds ${verdict.max} devices — remove one first`);
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2054
2136
|
const listWrites = [];
|
|
2055
2137
|
if (patch.nonBlocking !== void 0) listWrites.push(this.config.set("nonBlocking", patch.nonBlocking.map((l) => ({
|
|
2056
2138
|
mode: l.mode,
|
|
2057
2139
|
deviceIds: [...l.deviceIds]
|
|
2058
2140
|
}))));
|
|
2141
|
+
if (patch.blocking !== void 0) listWrites.push(this.config.set("blocking", patch.blocking.map((l) => ({
|
|
2142
|
+
mode: l.mode,
|
|
2143
|
+
deviceIds: [...l.deviceIds]
|
|
2144
|
+
}))));
|
|
2145
|
+
if (patch.secureOnArmOff !== void 0) listWrites.push(this.config.set("secureOnArmOff", patch.secureOnArmOff.map((l) => ({
|
|
2146
|
+
mode: l.mode,
|
|
2147
|
+
deviceIds: [...l.deviceIds]
|
|
2148
|
+
}))));
|
|
2059
2149
|
let membershipChanged = null;
|
|
2060
2150
|
if (membership !== void 0) {
|
|
2061
|
-
const result = applyNonBlockingEdit(
|
|
2151
|
+
const result = applyNonBlockingEdit(modeDeviceListFromPersisted(this.config.get("nonBlocking")), membership);
|
|
2062
2152
|
if (result.kind === "applied") {
|
|
2063
2153
|
membershipChanged = result.changed;
|
|
2064
2154
|
if (result.changed) listWrites.push(this.config.set("nonBlocking", result.lists.map((l) => ({
|
|
@@ -2067,6 +2157,26 @@ var NcAlarmPanelDevice = class extends BaseDevice {
|
|
|
2067
2157
|
}))));
|
|
2068
2158
|
}
|
|
2069
2159
|
}
|
|
2160
|
+
if (blockingEdit !== void 0) {
|
|
2161
|
+
const result = applyBlockingEdit(modeDeviceListFromPersisted(this.config.get("blocking")), blockingEdit);
|
|
2162
|
+
if (result.kind === "applied" && result.changed) {
|
|
2163
|
+
membershipChanged = true;
|
|
2164
|
+
listWrites.push(this.config.set("blocking", result.lists.map((l) => ({
|
|
2165
|
+
mode: l.mode,
|
|
2166
|
+
deviceIds: [...l.deviceIds]
|
|
2167
|
+
}))));
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
if (secureEdit !== void 0) {
|
|
2171
|
+
const result = applySecureOnArmEdit(modeDeviceListFromPersisted(this.config.get("secureOnArmOff")), secureEdit);
|
|
2172
|
+
if (result.kind === "applied" && result.changed) {
|
|
2173
|
+
membershipChanged = true;
|
|
2174
|
+
listWrites.push(this.config.set("secureOnArmOff", result.lists.map((l) => ({
|
|
2175
|
+
mode: l.mode,
|
|
2176
|
+
deviceIds: [...l.deviceIds]
|
|
2177
|
+
}))));
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2070
2180
|
const persistedDelays = modeDelaysFromPersisted(this.config.get("modeDelays"));
|
|
2071
2181
|
const beforeDelays = persistedDelays.entries;
|
|
2072
2182
|
const afterDelays = edits.length > 0 ? applyModeDelaysEdits(beforeDelays, edits) : beforeDelays;
|
|
@@ -2205,7 +2315,7 @@ var NcAlarmPanelDevice = class extends BaseDevice {
|
|
|
2205
2315
|
if (read.verdict.kind === "refused") return this.refuse(mode, read.verdict.blocking, now);
|
|
2206
2316
|
return this.settleArm(mode, read.verdict.excluded.map((device) => ({
|
|
2207
2317
|
device,
|
|
2208
|
-
why:
|
|
2318
|
+
why: this.exclusionWhyFor(mode, device)
|
|
2209
2319
|
})), now);
|
|
2210
2320
|
}
|
|
2211
2321
|
/**
|
|
@@ -2254,12 +2364,14 @@ var NcAlarmPanelDevice = class extends BaseDevice {
|
|
|
2254
2364
|
return outcome;
|
|
2255
2365
|
}
|
|
2256
2366
|
const tolerated = this.nonBlockingFor(held.mode);
|
|
2367
|
+
const forceBlock = this.blockingFor(held.mode);
|
|
2257
2368
|
const unknown = new Set(read.openings.unknown);
|
|
2258
2369
|
if (read.verdict.kind === "refused") {
|
|
2259
2370
|
const plain = decideArm({
|
|
2260
2371
|
mode: held.mode,
|
|
2261
2372
|
open: read.openings.open,
|
|
2262
|
-
nonBlocking: tolerated
|
|
2373
|
+
nonBlocking: tolerated,
|
|
2374
|
+
blocking: forceBlock
|
|
2263
2375
|
});
|
|
2264
2376
|
const blockingNow = plain.kind === "refused" ? plain.blocking : read.verdict.blocking;
|
|
2265
2377
|
const shownIds = new Set(blockingNow.map((d) => d.deviceId));
|
|
@@ -2389,10 +2501,17 @@ var NcAlarmPanelDevice = class extends BaseDevice {
|
|
|
2389
2501
|
error: String(err)
|
|
2390
2502
|
};
|
|
2391
2503
|
}
|
|
2504
|
+
const toSecure = openings.open.filter((d) => alarmDeviceSecureOnArm({
|
|
2505
|
+
controllable: d.controllable,
|
|
2506
|
+
deviceId: d.deviceId,
|
|
2507
|
+
secureOnArmOff: this.secureOnArmOffFor(mode)
|
|
2508
|
+
}));
|
|
2509
|
+
if (toSecure.length > 0) this.armGuard?.secureOnArm(toSecure);
|
|
2392
2510
|
const verdict = decideArm({
|
|
2393
2511
|
mode,
|
|
2394
2512
|
open: openings.open,
|
|
2395
2513
|
nonBlocking: this.nonBlockingFor(mode),
|
|
2514
|
+
blocking: this.blockingFor(mode),
|
|
2396
2515
|
...acknowledged !== void 0 ? { acknowledged } : {}
|
|
2397
2516
|
});
|
|
2398
2517
|
return {
|
|
@@ -2417,7 +2536,28 @@ var NcAlarmPanelDevice = class extends BaseDevice {
|
|
|
2417
2536
|
}
|
|
2418
2537
|
/** This mode's non-blocking ids, from the persisted lists. */
|
|
2419
2538
|
nonBlockingFor(mode) {
|
|
2420
|
-
return
|
|
2539
|
+
return this.modeListIds("nonBlocking", mode);
|
|
2540
|
+
}
|
|
2541
|
+
/** Controllable openings that force-block when open. */
|
|
2542
|
+
blockingFor(mode) {
|
|
2543
|
+
return this.modeListIds("blocking", mode);
|
|
2544
|
+
}
|
|
2545
|
+
/** Controllable openings that opt out of secure-on-arm. */
|
|
2546
|
+
secureOnArmOffFor(mode) {
|
|
2547
|
+
return this.modeListIds("secureOnArmOff", mode);
|
|
2548
|
+
}
|
|
2549
|
+
modeListIds(key, mode) {
|
|
2550
|
+
return modeDeviceListFromPersisted(this.config.get(key)).find((l) => l.mode === mode)?.deviceIds ?? [];
|
|
2551
|
+
}
|
|
2552
|
+
/** Why an open device was armed around on a plain (non–Arm-anyway) arm. */
|
|
2553
|
+
exclusionWhyFor(mode, device) {
|
|
2554
|
+
if (this.nonBlockingFor(mode).includes(device.deviceId)) return "non-blocking";
|
|
2555
|
+
if (alarmDeviceSecureOnArm({
|
|
2556
|
+
controllable: device.controllable,
|
|
2557
|
+
deviceId: device.deviceId,
|
|
2558
|
+
secureOnArmOff: this.secureOnArmOffFor(mode)
|
|
2559
|
+
})) return "secure-on-arm";
|
|
2560
|
+
return "non-blocking";
|
|
2421
2561
|
}
|
|
2422
2562
|
/**
|
|
2423
2563
|
* Arm, with these exclusions.
|
|
@@ -8610,6 +8750,7 @@ function sameWord(a, b) {
|
|
|
8610
8750
|
* therefore moves the table with the arm.
|
|
8611
8751
|
*/
|
|
8612
8752
|
function alarmSensorStateOf(deviceId, opening, online) {
|
|
8753
|
+
const controllable = opening?.kind === "reading" ? isAlarmControllableCap(opening.cap) : false;
|
|
8613
8754
|
const verdict = classifyCoveredOpening(opening);
|
|
8614
8755
|
switch (verdict.kind) {
|
|
8615
8756
|
case "unknown": return {
|
|
@@ -8617,27 +8758,31 @@ function alarmSensorStateOf(deviceId, opening, online) {
|
|
|
8617
8758
|
reading: "unknown",
|
|
8618
8759
|
state: null,
|
|
8619
8760
|
unknownWhy: verdict.why,
|
|
8620
|
-
online
|
|
8761
|
+
online,
|
|
8762
|
+
controllable
|
|
8621
8763
|
};
|
|
8622
8764
|
case "open": return {
|
|
8623
8765
|
deviceId,
|
|
8624
8766
|
reading: "open",
|
|
8625
8767
|
state: verdict.state,
|
|
8626
8768
|
unknownWhy: null,
|
|
8627
|
-
online
|
|
8769
|
+
online,
|
|
8770
|
+
controllable: verdict.controllable
|
|
8628
8771
|
};
|
|
8629
8772
|
case "skip": return opening?.kind === "reading" ? {
|
|
8630
8773
|
deviceId,
|
|
8631
8774
|
reading: "closed",
|
|
8632
8775
|
state: opening.state,
|
|
8633
8776
|
unknownWhy: null,
|
|
8634
|
-
online
|
|
8777
|
+
online,
|
|
8778
|
+
controllable
|
|
8635
8779
|
} : {
|
|
8636
8780
|
deviceId,
|
|
8637
8781
|
reading: "not-opening",
|
|
8638
8782
|
state: null,
|
|
8639
8783
|
unknownWhy: null,
|
|
8640
|
-
online
|
|
8784
|
+
online,
|
|
8785
|
+
controllable: false
|
|
8641
8786
|
};
|
|
8642
8787
|
}
|
|
8643
8788
|
}
|
|
@@ -19986,19 +20131,39 @@ function planSummaryDevices(rule, isDead, guard) {
|
|
|
19986
20131
|
notes: notes.notes
|
|
19987
20132
|
};
|
|
19988
20133
|
}
|
|
20134
|
+
function stripDeadFromLists(lists, isDead) {
|
|
20135
|
+
const dead = lists.flatMap((list) => list.deviceIds.filter(isDead));
|
|
20136
|
+
if (dead.length === 0) return {
|
|
20137
|
+
next: lists,
|
|
20138
|
+
dead
|
|
20139
|
+
};
|
|
20140
|
+
return {
|
|
20141
|
+
dead,
|
|
20142
|
+
next: lists.map((list) => ({
|
|
20143
|
+
...list,
|
|
20144
|
+
deviceIds: list.deviceIds.filter((id) => !isDead(id))
|
|
20145
|
+
}))
|
|
20146
|
+
};
|
|
20147
|
+
}
|
|
19989
20148
|
function planAlarmDevices(alarm, isDead) {
|
|
19990
20149
|
if (alarm === null) return null;
|
|
19991
|
-
const
|
|
19992
|
-
const
|
|
20150
|
+
const nonBlocking = stripDeadFromLists(alarm.nonBlocking, isDead);
|
|
20151
|
+
const blocking = stripDeadFromLists(alarm.blocking, isDead);
|
|
20152
|
+
const secureOnArmOff = stripDeadFromLists(alarm.secureOnArmOff, isDead);
|
|
19993
20153
|
const forgetExcluded = alarm.excluded.filter(isDead);
|
|
19994
|
-
|
|
20154
|
+
const deadIds = [
|
|
20155
|
+
...nonBlocking.dead,
|
|
20156
|
+
...blocking.dead,
|
|
20157
|
+
...secureOnArmOff.dead,
|
|
20158
|
+
...forgetExcluded
|
|
20159
|
+
];
|
|
20160
|
+
if (deadIds.length === 0) return null;
|
|
19995
20161
|
return {
|
|
19996
|
-
dropped: deviceSubjects([...new Set(
|
|
20162
|
+
dropped: deviceSubjects([...new Set(deadIds)]),
|
|
19997
20163
|
droppedKind: "device",
|
|
19998
|
-
...
|
|
19999
|
-
|
|
20000
|
-
|
|
20001
|
-
})) } : {},
|
|
20164
|
+
...nonBlocking.dead.length > 0 ? { nonBlocking: nonBlocking.next } : {},
|
|
20165
|
+
...blocking.dead.length > 0 ? { blocking: blocking.next } : {},
|
|
20166
|
+
...secureOnArmOff.dead.length > 0 ? { secureOnArmOff: secureOnArmOff.next } : {},
|
|
20002
20167
|
forgetExcluded
|
|
20003
20168
|
};
|
|
20004
20169
|
}
|
|
@@ -20040,6 +20205,8 @@ function referencedDeviceIds(snapshot) {
|
|
|
20040
20205
|
for (const rule of snapshot.timelapse) add(rule.deviceIds);
|
|
20041
20206
|
for (const rule of snapshot.summary) add(rule.deviceIds);
|
|
20042
20207
|
for (const list of snapshot.alarm?.nonBlocking ?? []) add(list.deviceIds);
|
|
20208
|
+
for (const list of snapshot.alarm?.blocking ?? []) add(list.deviceIds);
|
|
20209
|
+
for (const list of snapshot.alarm?.secureOnArmOff ?? []) add(list.deviceIds);
|
|
20043
20210
|
add(snapshot.alarm?.excluded);
|
|
20044
20211
|
add(snapshot.mutedDeviceIds);
|
|
20045
20212
|
return ids;
|
|
@@ -20384,6 +20551,8 @@ var NcDeletedSubjectPruner = class {
|
|
|
20384
20551
|
summary: this.writable("summary", this.deps.summary.list()),
|
|
20385
20552
|
alarm: panel !== null && settings !== void 0 ? {
|
|
20386
20553
|
nonBlocking: settings.nonBlocking,
|
|
20554
|
+
blocking: settings.blocking,
|
|
20555
|
+
secureOnArmOff: settings.secureOnArmOff,
|
|
20387
20556
|
announceTargets: settings.announceTargets,
|
|
20388
20557
|
excluded: panel.excludedDevices()
|
|
20389
20558
|
} : null,
|
|
@@ -20540,6 +20709,8 @@ var NcDeletedSubjectPruner = class {
|
|
|
20540
20709
|
...NO_SNAPSHOT,
|
|
20541
20710
|
alarm: {
|
|
20542
20711
|
nonBlocking: settings.nonBlocking,
|
|
20712
|
+
blocking: settings.blocking,
|
|
20713
|
+
secureOnArmOff: settings.secureOnArmOff,
|
|
20543
20714
|
announceTargets: settings.announceTargets,
|
|
20544
20715
|
excluded: panel.excludedDevices()
|
|
20545
20716
|
}
|
|
@@ -20548,6 +20719,8 @@ var NcDeletedSubjectPruner = class {
|
|
|
20548
20719
|
try {
|
|
20549
20720
|
const patch = {
|
|
20550
20721
|
...edit.nonBlocking !== void 0 ? { nonBlocking: edit.nonBlocking } : {},
|
|
20722
|
+
...edit.blocking !== void 0 ? { blocking: edit.blocking } : {},
|
|
20723
|
+
...edit.secureOnArmOff !== void 0 ? { secureOnArmOff: edit.secureOnArmOff } : {},
|
|
20551
20724
|
...edit.announceTargets !== void 0 ? { announceTargets: [...edit.announceTargets] } : {}
|
|
20552
20725
|
};
|
|
20553
20726
|
if (Object.keys(patch).length > 0) await panel.applySettings(patch);
|
|
@@ -35550,6 +35723,8 @@ var NC_ALARM_SETTINGS_FALLBACK = {
|
|
|
35550
35723
|
...DEFAULT_DELAYS,
|
|
35551
35724
|
announceTargets: [],
|
|
35552
35725
|
nonBlocking: [],
|
|
35726
|
+
blocking: [],
|
|
35727
|
+
secureOnArmOff: [],
|
|
35553
35728
|
modeDelays: []
|
|
35554
35729
|
};
|
|
35555
35730
|
/**
|
|
@@ -38554,6 +38729,9 @@ var NotificationCenter = class {
|
|
|
38554
38729
|
alarmArmGuard() {
|
|
38555
38730
|
return {
|
|
38556
38731
|
openings: (mode) => this.alarmOpenings(mode),
|
|
38732
|
+
secureOnArm: (devices) => {
|
|
38733
|
+
this.secureDevicesOnArm(devices);
|
|
38734
|
+
},
|
|
38557
38735
|
announceRefusal: (input) => this.announceArmRefused(input),
|
|
38558
38736
|
announceCheckFailed: (input) => this.announceArmCheckFailed(input)
|
|
38559
38737
|
};
|
|
@@ -38620,7 +38798,9 @@ var NotificationCenter = class {
|
|
|
38620
38798
|
if (verdict.kind === "open") open.push({
|
|
38621
38799
|
deviceId,
|
|
38622
38800
|
name: name(deviceId),
|
|
38623
|
-
state: verdict.state
|
|
38801
|
+
state: verdict.state,
|
|
38802
|
+
controllable: verdict.controllable,
|
|
38803
|
+
cap: verdict.cap
|
|
38624
38804
|
});
|
|
38625
38805
|
}
|
|
38626
38806
|
this.logger.info("alarm arm check", {
|
|
@@ -38639,6 +38819,47 @@ var NotificationCenter = class {
|
|
|
38639
38819
|
};
|
|
38640
38820
|
}
|
|
38641
38821
|
/**
|
|
38822
|
+
* Fire-and-forget secure actuation for controllable openings on arm.
|
|
38823
|
+
* Failures are WARN per device — they never refuse the arm.
|
|
38824
|
+
*/
|
|
38825
|
+
async secureDevicesOnArm(devices) {
|
|
38826
|
+
for (const device of devices) {
|
|
38827
|
+
const actuation = device.cap !== void 0 ? secureActuationFor(device.cap) : null;
|
|
38828
|
+
if (actuation === null) continue;
|
|
38829
|
+
try {
|
|
38830
|
+
await this.actuateWithAttribution({
|
|
38831
|
+
deviceId: device.deviceId,
|
|
38832
|
+
cap: actuation.cap,
|
|
38833
|
+
method: actuation.method,
|
|
38834
|
+
args: {
|
|
38835
|
+
deviceId: device.deviceId,
|
|
38836
|
+
...actuation.args
|
|
38837
|
+
}
|
|
38838
|
+
});
|
|
38839
|
+
this.logger.info("alarm secure-on-arm actuated", {
|
|
38840
|
+
tags: { deviceId: device.deviceId },
|
|
38841
|
+
meta: {
|
|
38842
|
+
name: device.name,
|
|
38843
|
+
state: device.state,
|
|
38844
|
+
cap: actuation.cap,
|
|
38845
|
+
method: actuation.method
|
|
38846
|
+
}
|
|
38847
|
+
});
|
|
38848
|
+
} catch (err) {
|
|
38849
|
+
this.logger.warn("alarm secure-on-arm actuation failed — arm continues", {
|
|
38850
|
+
tags: { deviceId: device.deviceId },
|
|
38851
|
+
meta: {
|
|
38852
|
+
name: device.name,
|
|
38853
|
+
state: device.state,
|
|
38854
|
+
cap: actuation.cap,
|
|
38855
|
+
method: actuation.method,
|
|
38856
|
+
error: String(err)
|
|
38857
|
+
}
|
|
38858
|
+
});
|
|
38859
|
+
}
|
|
38860
|
+
}
|
|
38861
|
+
}
|
|
38862
|
+
/**
|
|
38642
38863
|
* The refusal, as an ordinary notification.
|
|
38643
38864
|
*
|
|
38644
38865
|
* Same path every alarm announcement takes (D126: the alarm speaks through
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-D553qWb_.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|