@camstack/addon-provider-dreo 0.2.116 → 0.2.117

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.
Files changed (3) hide show
  1. package/dist/addon.js +892 -325
  2. package/dist/addon.mjs +892 -325
  3. package/package.json +1 -3
package/dist/addon.mjs CHANGED
@@ -36,7 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
36
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
37
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
38
38
  //#endregion
39
- //#region ../types/dist/event-category-C5xZWqz6.mjs
39
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
40
40
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
41
41
  EventCategory["SystemBoot"] = "system.boot";
42
42
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -569,6 +569,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
569
569
  */
570
570
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
571
571
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
572
+ /**
573
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
574
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
575
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
576
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
577
+ * for a camera with no attached sensor). Providers must not emit
578
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
579
+ * keeps it so (camera-grid is a named, deferred exception).
580
+ */
572
581
  EventCategory["ProviderMotion"] = "provider.motion";
573
582
  EventCategory["ProviderDetection"] = "provider.detection";
574
583
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5407,7 +5416,7 @@ var ZodIssueCode = {
5407
5416
  var ZodFirstPartyTypeKind;
5408
5417
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5409
5418
  //#endregion
5410
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5419
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5411
5420
  /**
5412
5421
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5413
5422
  * window to float samples (D455).
@@ -7450,7 +7459,7 @@ function errMsg(err) {
7450
7459
  return String(err);
7451
7460
  }
7452
7461
  //#endregion
7453
- //#region ../types/dist/composition-Dq42XWp0.mjs
7462
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
7454
7463
  /**
7455
7464
  * The ffmpeg build every CamStack node downloads, per platform and arch.
7456
7465
  *
@@ -7504,21 +7513,20 @@ function portable(target) {
7504
7513
  }
7505
7514
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
7506
7515
  /**
7507
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7508
- * valutatore puro del suo FRONTE.
7516
+ * THE table "which boolean of this device type counts as HIGH", and the
7517
+ * pure evaluator of its EDGE.
7509
7518
  *
7510
- * Viveva dentro il builtin virtual-doorbell
7511
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7512
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7513
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7514
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7515
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7516
- * SPOSTA qui e il doorbell la ri-esporta.
7519
+ * ONE table for everyone who asks "is this device HIGH?": the
7520
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
7521
+ * sensor markers, the orchestrator's camera-sensors bridge and
7522
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
7523
+ * A second copy would diverge at the first cap added, and the symptom — "the
7524
+ * sensor rings the doorbell but does not record" — is exactly D62.
7517
7525
  *
7518
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7519
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7520
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7521
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7526
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
7527
+ * two must not be unified: that one answers "what is the state WORD for a
7528
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
7529
+ * boolean's EDGE counts". Deliberately different vocabularies.
7522
7530
  */
7523
7531
  /**
7524
7532
  * Known binary / switch source caps → the boolean slice field whose
@@ -9127,22 +9135,22 @@ var CLASS_MAP_MACRO_TARGETS = [
9127
9135
  "package"
9128
9136
  ];
9129
9137
  /**
9130
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
9131
- * un operatore può selezionare.
9138
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
9139
+ * an operator can select.
9132
9140
  *
9133
- * Sono le tre offerte dallo step `object-detection`
9141
+ * They are the three offered by the `object-detection` step
9134
9142
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
9135
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
9136
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
9137
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
9138
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
9143
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
9144
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
9145
+ * `package-detection`, whose enablement is driven by zones, and offering the
9146
+ * same word twice has already made an operator turn on the COCO proxy
9139
9147
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
9140
9148
  *
9141
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
9142
- * dello step e una seconda volta come union `FirstLevelMacro`
9143
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
9144
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
9145
- * successiva.
9149
+ * ONE list. Before today the same three were hand-written in the step's offer
9150
+ * and a second time as the union `FirstLevelMacro`
9151
+ * (`types/detection.ts`); a third copy for the recording trigger
9152
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
9153
+ * invisible.
9146
9154
  */
9147
9155
  var FIRST_LEVEL_MACRO_CLASSES = [
9148
9156
  "person",
@@ -9207,17 +9215,17 @@ var RecordingStorageModeSchema = _enum([
9207
9215
  "on-device-decision"
9208
9216
  ]);
9209
9217
  /**
9210
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
9211
- * tre offerte dallo step `object-detection`, da UNA lista
9218
+ * The macro classes that can open a recording window — the same
9219
+ * three offered by the `object-detection` step, from ONE list
9212
9220
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
9213
9221
  */
9214
9222
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
9215
9223
  /**
9216
- * True quando `values` non ripete un elemento.
9224
+ * True when `values` does not repeat an element.
9217
9225
  *
9218
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
9219
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
9220
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
9226
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
9227
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
9228
+ * would count its windows twice in `segmentMissedByMs`.
9221
9229
  */
9222
9230
  var noDuplicates = (values) => new Set(values).size === values.length;
9223
9231
  /** Which detectors trigger an `events`-mode band. */
@@ -9225,34 +9233,34 @@ var RecordingTriggersSchema = object({
9225
9233
  motion: boolean().optional(),
9226
9234
  audioThresholdDbfs: number().optional(),
9227
9235
  /**
9228
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
9229
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
9230
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
9231
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
9236
+ * The macro classes whose detection opens a window. ABSENT = the source
9237
+ * is not listened to; an EMPTY array is rejected, because "events band, object
9238
+ * trigger on, no class" is the same shape "enabled and records
9239
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
9232
9240
  *
9233
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
9234
- * quelle che hanno attraversato `enabledMacroClasses`, i
9235
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
9236
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
9237
- * finestre — vedi `recorder/object-trigger.ts`.
9241
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
9242
+ * those that went through `enabledMacroClasses`, the
9243
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
9244
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
9245
+ * windows — see `recorder/object-trigger.ts`.
9238
9246
  */
9239
9247
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
9240
9248
  /**
9241
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
9242
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
9249
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
9250
+ * is not listened to; an empty array is rejected for the same reason as
9243
9251
  * `objectClasses`.
9244
9252
  *
9245
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
9246
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
9247
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
9248
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9249
- * device (D12) — mai un elenco globale di cap.
9253
+ * These are SOURCE device ids, not cameras: the band names them, so the
9254
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
9255
+ * does no RPC. The OFFER from which the operator picks them is another question, and
9256
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9257
+ * device (D12) — never a global list of caps.
9250
9258
  *
9251
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9252
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9253
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9254
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
9255
- * registrare.
9259
+ * What "high" means depends on the device TYPE and is not decided here:
9260
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
9261
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
9262
+ * the level: a contact found already open at runner restart does not
9263
+ * record.
9256
9264
  */
9257
9265
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9258
9266
  });
@@ -10329,7 +10337,7 @@ var DecoderSessionConfigSchema = object({
10329
10337
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
10330
10338
  * thing: the logging settings document on the `system` cap. Two authorities
10331
10339
  * over the values is the exact defect
10332
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
10340
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
10333
10341
  * remove; re-introducing it from the cure side would be grotesque.
10334
10342
  *
10335
10343
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -12040,7 +12048,7 @@ var BrokerStatusEnum = _enum([
12040
12048
  "unreachable",
12041
12049
  "error"
12042
12050
  ]);
12043
- var BrokerInfoSchema$1 = object({
12051
+ var BrokerInfoSchema = object({
12044
12052
  /** Stable broker id. Persisted; survives addon restarts. */
12045
12053
  id: string(),
12046
12054
  /** Addon id of the provider that OWNS this broker.
@@ -12173,7 +12181,7 @@ var GetStateInputSchema = object({
12173
12181
  * HA: entity_id (returns the cached entity state). */
12174
12182
  key: string()
12175
12183
  });
12176
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12184
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12177
12185
  kind: "mutation",
12178
12186
  auth: "admin"
12179
12187
  }), method(RemoveInputSchema, _void(), {
@@ -13884,7 +13892,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
13884
13892
  *
13885
13893
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
13886
13894
  * was wrong — corrected 2026-08-26 after the hop map
13887
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
13895
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
13888
13896
  * There is **no Zod parse at all** between the door and the engine: the
13889
13897
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
13890
13898
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -14764,7 +14772,17 @@ var SiteZoneSchema = object({
14764
14772
  var ProviderStatusSchema = object({
14765
14773
  connected: boolean(),
14766
14774
  deviceCount: number(),
14767
- error: string().optional()
14775
+ error: string().optional(),
14776
+ /**
14777
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14778
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14779
+ * which every provider bundles, so only a provider BUILT from D696-amended
14780
+ * code says it. ABSENT means an older provider that may still write it (raw
14781
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14782
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14783
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14784
+ */
14785
+ motionSliceWriter: literal("orchestrator").optional()
14768
14786
  });
14769
14787
  object({
14770
14788
  externalId: string(),
@@ -15643,109 +15661,10 @@ method(object({
15643
15661
  deviceIds: array(number()).readonly(),
15644
15662
  caps: array(string()).readonly().optional()
15645
15663
  }), record(string(), record(string(), unknown().nullable())));
15646
- /**
15647
- * Doorbell button cap. Two kinds of providers coexist behind this cap
15648
- * name (same pattern as `snapshot`):
15649
- *
15650
- * - **Native** providers: registered per-device by device-driver
15651
- * addons via `ctx.registerNativeCap` — either on a
15652
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
15653
- * or directly on the camera (Reolink registers at camera level).
15654
- * Emits an `onPressed` event every time the firmware pushes a
15655
- * ring; status tracks the last press and a pressCount since start
15656
- * (diagnostic).
15657
- *
15658
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
15659
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
15660
- * device (contact / switch / event-emitter …) into a doorbell for
15661
- * a camera. `defaultActive: false` — the operator explicitly binds
15662
- * it per camera in the device-bindings UI, then picks the source
15663
- * device + trigger in the per-device settings.
15664
- *
15665
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
15666
- * — subscribers listening at the camera level receive ring events
15667
- * with `via[]` populated. No code on the parent needed.
15668
- */
15669
- var DoorbellStatusSchema = object({
15670
- /** Ms epoch of the last press. null = never observed since this provider started. */
15671
- lastPressedAt: number().nullable(),
15672
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15673
- pressCountSinceStart: number()
15674
- });
15675
- var DoorbellPressEventSchema = object({
15676
- deviceId: number(),
15677
- timestamp: number()
15678
- });
15679
- /**
15680
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15681
- * virtual-doorbell trigger devices, exactly what the wrapper's
15682
- * `doorbellSources` persists (as `{ deviceId }` records).
15683
- */
15684
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15685
- /**
15686
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
15687
- * doorbell, owned by the `virtual-doorbell` wrapper over its
15688
- * `doorbellSources` store (D648). A source rings when one of its
15689
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
15690
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
15691
- * reports it, it never writes it.
15692
- */
15693
- var DOORBELL_SOURCE_SLOT = {
15694
- id: "doorbell-source",
15695
- label: "Doorbell trigger devices",
15696
- description: "Any of these becoming active rings this camera's virtual doorbell: a binary sensor when it goes active, a switch when it turns on.",
15697
- shape: "association",
15698
- hostDeviceTypes: [DeviceType.Camera],
15699
- sourceCaps: SOURCE_CAPS,
15700
- cardinality: "many",
15701
- value: DoorbellSourceSlotValueSchema
15702
- };
15703
- var doorbellCapability = {
15704
- name: "doorbell",
15705
- scope: "device",
15706
- deviceNative: true,
15707
- mode: "singleton",
15708
- kind: "wrapper",
15709
- defaultActive: false,
15710
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
15711
- extensionSlots: [DOORBELL_SOURCE_SLOT],
15712
- methods: {},
15713
- events: {
15714
- /**
15715
- * Fires once per physical press. Reolink delivers via Baichuan
15716
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
15717
- * release/duration — it's a pulse.
15718
- */
15719
- onPressed: {
15720
- data: DoorbellPressEventSchema,
15721
- fromState: {
15722
- field: "lastPressedAt",
15723
- on: "advance"
15724
- }
15725
- } },
15726
- status: {
15727
- schema: DoorbellStatusSchema,
15728
- kind: "push"
15729
- },
15730
- /**
15731
- * Runtime-state slice — last press timestamp + lifetime press count.
15732
- * Mirrored by the kernel and readable via
15733
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
15734
- * without subscribing.
15735
- */
15736
- runtimeState: DoorbellStatusSchema,
15737
- /**
15738
- * Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
15739
- *
15740
- * See `RuntimeStateDurability`. Enforced by
15741
- * `scripts/check-runtime-state-durability.ts`.
15742
- */
15743
- durability: "restored"
15744
- };
15745
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15746
- DeviceType.Camera, DeviceType.Camera;
15664
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15665
+ DeviceType.Camera;
15747
15666
  /** A slot's editable value, discriminated on `slot`. */
15748
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15667
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15749
15668
  DeviceType.Camera;
15750
15669
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15751
15670
  state: literal("unreachable"),
@@ -15782,10 +15701,11 @@ var ExtensionSlotSourceSchema = object({
15782
15701
  });
15783
15702
  /**
15784
15703
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15785
- * reported read-only, named, never written through this contract (D62). The
15786
- * virtual doorbell's sources ring only while the wrapper is bound to the
15787
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15788
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15704
+ * reported read-only, named, never written through this contract (D62) — e.g.
15705
+ * a slot whose sources act only while a wrapper is bound to the host, a
15706
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15707
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15708
+ * not be read; it is not "inactive" (D315).
15789
15709
  */
15790
15710
  var ExtensionSlotActivationSchema = object({
15791
15711
  state: _enum([
@@ -15801,7 +15721,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15801
15721
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15802
15722
  slotRef: string(),
15803
15723
  slot: ExtensionSlotIdSchema,
15804
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15724
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15805
15725
  authority: string(),
15806
15726
  activation: ExtensionSlotActivationSchema.nullable(),
15807
15727
  value: ExtensionSlotValueSchema,
@@ -16079,7 +15999,7 @@ method(object({
16079
15999
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16080
16000
  * ends in a log line, and a log line is the thing the operator asked to stop
16081
16001
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16082
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
16002
+ * ricontrolliamo tutti questi punti"* [can we instrument these errors in the meantime? That way next round we recheck all these points]. Reading them meant grepping Loki and
16083
16003
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16084
16004
  * media blackout were both diagnosed. The counters stay; this is where they can
16085
16005
  * be READ.
@@ -17455,7 +17375,7 @@ var BrokerStatusSchema$1 = _enum([
17455
17375
  "unreachable",
17456
17376
  "tls-error"
17457
17377
  ]);
17458
- var BrokerInfoSchema = object({
17378
+ var BrokerInfoSchema$1 = object({
17459
17379
  id: string(),
17460
17380
  name: string(),
17461
17381
  url: string(),
@@ -17518,7 +17438,7 @@ var StatusSchema = object({
17518
17438
  brokerCount: number(),
17519
17439
  embeddedRunning: boolean()
17520
17440
  });
17521
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17441
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17522
17442
  kind: "mutation",
17523
17443
  auth: "admin"
17524
17444
  }), method(IdInputSchema, _void(), {
@@ -19732,78 +19652,16 @@ var NcRuleInputSchema = object({
19732
19652
  */
19733
19653
  confirm: NcConfirmSchema.optional(),
19734
19654
  /**
19735
- * WAIT for face/plate recognition before saying anything.
19736
- *
19737
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
19738
- * send; the identity is neither. A face is confirmed after `confirmFrames`
19739
- * agreeing observations — p50 **11.4 s** after the track was first seen,
19740
- * measured on this hub — and an `immediate` rule enqueues on the first object
19741
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
19742
- * immediate path, and no amount of media re-resolution fixes a sentence.
19743
- *
19744
- * Only two honest answers exist, and this flag picks between them. It has
19745
- * effect ONLY on a rule that declares a recognition scope
19746
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
19747
- * other rule there is nothing to wait for and the flag is inert.
19748
- *
19749
- * | value | what happens |
19750
- * | --- | --- |
19751
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
19752
- * | absent / `false` | it fires at once WITHOUT the name, and if recognition lands before the track closes a SECOND, "…is Gianluca" notification follows (one per track, per rule, per target) |
19753
- *
19754
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19755
- * on the addon cap path, and absent has to keep meaning exactly what every
19756
- * rule authored before this field meant.
19757
- *
19758
- * The cost of `true` is stated here because the editor states it too: a rule
19759
- * that waits also inherits track-close SEMANTICS — its `zones` condition
19760
- * tests every zone the track visited and a `crossing` condition can no longer
19761
- * be satisfied, because a closed track carries no crossing.
19655
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
19656
+ * seconds; the rule sends ONE message when the window closes — early, once every
19657
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
19658
+ * the rule matched, with one mosaic tile per subject.
19659
+ * Absent = plain immediate (one message per track, at the first match).
19660
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
19661
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
19662
+ * path does not run Zod defaults.
19762
19663
  */
19763
- waitForEnhancement: boolean().optional(),
19764
- /**
19765
- * GROUP a burst of subjects into ONE notification that grows.
19766
- *
19767
- * Seconds of quiet after the last matching subject before the burst is
19768
- * considered over. While it is open, the first subject enqueues immediately —
19769
- * **exactly as today, with no added latency** — and every real growth (a new
19770
- * subject, or a name confirmed on one already in it) REPLACES that
19771
- * notification with an updated one naming everybody. The push carries the
19772
- * group's own coalescing tag, so the phone replaces rather than stacks.
19773
- *
19774
- * `0` / absent = off, and off is today's behaviour byte for byte.
19775
- *
19776
- * ### Why an idle cutoff and not a window
19777
- *
19778
- * The measured seven-person arrival on device 590 spans 110 s with every
19779
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
19780
- * idle cutoff holds it as one and ends it when the arrival actually ends.
19781
- * 30 s is a widely shipped value for the same decision.
19782
- *
19783
- * ### What it replaces
19784
- *
19785
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
19786
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
19787
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
19788
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
19789
- * A group collapses the same volume by MERGING, so the cooldown becomes a
19790
- * budget over GROUPS — which is what it always meant — and a growth is never
19791
- * throttled by the window its own first member spent.
19792
- *
19793
- * ### Interaction with {@link waitForEnhancement}
19794
- *
19795
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
19796
- * TRACK CLOSE, so with both set the group is opened by the first member to
19797
- * CLOSE — already carrying its name — and grows as later members close. That
19798
- * is later, and complete. With grouping alone the group opens on the first
19799
- * object event and picks up names as they are confirmed, through the growth
19800
- * path. Neither combination fires twice for one subject.
19801
- *
19802
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19803
- * on the addon cap path, so absent must keep meaning what it meant before this
19804
- * field existed.
19805
- */
19806
- groupIdleSec: number().int().min(0).max(600).optional()
19664
+ groupingSec: number().int().min(5).max(60).optional()
19807
19665
  });
19808
19666
  /**
19809
19667
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -19851,9 +19709,10 @@ var NcRuleClearableKeySchema = _enum([
19851
19709
  "targetUsers",
19852
19710
  "snoozeOptions",
19853
19711
  "snoozeAllowGlobal",
19854
- "waitForEnhancement",
19855
19712
  "actions",
19856
19713
  "confirm",
19714
+ "groupingSec",
19715
+ "waitForEnhancement",
19857
19716
  "groupIdleSec"
19858
19717
  ]);
19859
19718
  var NcRuleUpdateInputSchema = object({
@@ -19875,9 +19734,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19875
19734
  */
19876
19735
  disabledTargetIds: array(string()).default([])
19877
19736
  });
19737
+ /**
19738
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19739
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
19740
+ * job is not an open state, and the alarm stays instant.
19741
+ */
19742
+ var NcStateSummarySectionIdSchema = _enum([
19743
+ "device-state",
19744
+ "streams",
19745
+ "battery",
19746
+ "consumables",
19747
+ "tanks",
19748
+ "detection-blind",
19749
+ "nodes",
19750
+ "addons",
19751
+ "updates"
19752
+ ]);
19878
19753
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
19879
19754
  var NcStateSummaryPreviewSectionSchema = object({
19880
- id: string(),
19755
+ id: NcStateSummarySectionIdSchema,
19881
19756
  status: _enum(["read", "unavailable"]),
19882
19757
  items: number().int().nonnegative(),
19883
19758
  reason: string().optional()
@@ -19887,7 +19762,7 @@ var NcStateSummaryPreviewSectionSchema = object({
19887
19762
  * a `rule` split (no `section`), one section's on a `section` split.
19888
19763
  */
19889
19764
  var NcStateSummaryPreviewRowSchema = object({
19890
- section: string().optional(),
19765
+ section: NcStateSummarySectionIdSchema.optional(),
19891
19766
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19892
19767
  title: string(),
19893
19768
  text: string(),
@@ -20324,6 +20199,29 @@ object({
20324
20199
  firstAt: number(),
20325
20200
  lastAt: number()
20326
20201
  });
20202
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20203
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20204
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20205
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20206
+ var NcAlarmModeDelaysListSchema = array(object({
20207
+ mode: AlarmArmModeSchema,
20208
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20209
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20210
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20211
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20212
+ var NcAlarmModeDelaysEditListSchema = array(object({
20213
+ mode: AlarmArmModeSchema,
20214
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20215
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20216
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20217
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20218
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20219
+ var NcAlarmNonBlockingEditSchema = object({
20220
+ mode: AlarmArmModeSchema,
20221
+ deviceId: number().int().positive(),
20222
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20223
+ nonBlocking: boolean()
20224
+ });
20327
20225
  /**
20328
20226
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20329
20227
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20332,10 +20230,10 @@ object({
20332
20230
  var NcAlarmNonBlockingListSchema = array(object({
20333
20231
  mode: AlarmArmModeSchema,
20334
20232
  deviceIds: array(number().int()).max(200)
20335
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20233
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20336
20234
  /**
20337
- * The three durations the panel's state machine runs on, who hears about its
20338
- * transitions, and which openings each mode tolerates.
20235
+ * The three durations — global, and per mode since D697 — the panel's state
20236
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20339
20237
  *
20340
20238
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20341
20239
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20345,15 +20243,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20345
20243
  */
20346
20244
  var NcAlarmSettingsSchema = object({
20347
20245
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20348
- exitDelaySec: number().int().min(0).max(600),
20246
+ exitDelaySec: NcAlarmDelaySecSchema,
20349
20247
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20350
- entryDelaySec: number().int().min(0).max(600),
20248
+ entryDelaySec: NcAlarmDelaySecSchema,
20351
20249
  /**
20352
20250
  * How long `triggered` lasts before the panel re-arms itself.
20353
20251
  * **0 = until an operator disarms it** — the behaviour before this field
20354
20252
  * existed, and therefore what an untouched install keeps doing.
20355
20253
  */
20356
- triggeredDurationSec: number().int().min(0).max(3600),
20254
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20357
20255
  /**
20358
20256
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20359
20257
  * remove after one release. Optional so an older admin's patch (which still
@@ -20376,17 +20274,30 @@ var NcAlarmSettingsSchema = object({
20376
20274
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20377
20275
  * parses as "every opening blocks" — the behaviour it was written under.
20378
20276
  */
20379
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20277
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20278
+ /**
20279
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20280
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20281
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20282
+ */
20283
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20380
20284
  });
20381
20285
  /**
20382
20286
  * Every field optional — a tab edits one control at a time.
20383
20287
  *
20384
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20385
- * remove an inner `.default()`, so a patch that never named the field would
20386
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20387
- * (the same trap {@link NcRulePatchSchema} documents).
20288
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20289
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20290
+ * named the field would parse to `[]` and wipe every mode's list on an
20291
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20292
+ * `modeDelays` means EDITS, not the stored overrides.
20388
20293
  */
20389
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20294
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20295
+ nonBlocking: NcAlarmNonBlockingListSchema,
20296
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20297
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20298
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20299
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20300
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20390
20301
  /**
20391
20302
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20392
20303
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20486,6 +20397,28 @@ var NcAlarmConfigSchema = object({
20486
20397
  */
20487
20398
  live: NcAlarmLiveSchema.optional()
20488
20399
  });
20400
+ var NcAlarmSensorReadingSchema = _enum([
20401
+ "open",
20402
+ "closed",
20403
+ "unknown",
20404
+ "not-opening"
20405
+ ]);
20406
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20407
+ var NcAlarmSensorStateSchema = object({
20408
+ deviceId: number().int().positive(),
20409
+ reading: NcAlarmSensorReadingSchema,
20410
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20411
+ state: string().nullable(),
20412
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20413
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20414
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20415
+ online: boolean().nullable()
20416
+ });
20417
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20418
+ var NcAlarmSensorsSchema = object({
20419
+ sensors: array(NcAlarmSensorStateSchema),
20420
+ readAt: number().int().nonnegative()
20421
+ });
20489
20422
  /**
20490
20423
  * ONE rule's demand on ONE camera's clip ring.
20491
20424
  *
@@ -20576,7 +20509,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20576
20509
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20577
20510
  kind: "mutation",
20578
20511
  auth: "admin"
20579
- });
20512
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20580
20513
  /**
20581
20514
  * Zod schemas for persisted record types.
20582
20515
  *
@@ -20923,12 +20856,26 @@ var CameraSensorRefSchema = object({
20923
20856
  function cameraSensorRefKey(ref) {
20924
20857
  return `${ref.addonId}/${ref.stableId}`;
20925
20858
  }
20926
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20927
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20928
- var CameraSensorsConfigSchema = object({
20929
- mode: CameraSensorsModeSchema,
20930
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20931
- }).superRefine((value, ctx) => {
20859
+ /**
20860
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20861
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20862
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20863
+ * camera's own motion counts only while a confirm sensor is active — with or
20864
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20865
+ */
20866
+ var CameraSensorModeSchema = _enum([
20867
+ "in-addition",
20868
+ "confirm",
20869
+ "replace"
20870
+ ]);
20871
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20872
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20873
+ /**
20874
+ * A camera's attached sensors. A CS-1 row carried an envelope
20875
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20876
+ * what the write stores (D672 rule 3), so it is never written again.
20877
+ */
20878
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20932
20879
  const seen = /* @__PURE__ */ new Set();
20933
20880
  value.sensors.forEach((ref, index) => {
20934
20881
  const key = cameraSensorRefKey(ref);
@@ -20940,39 +20887,41 @@ var CameraSensorsConfigSchema = object({
20940
20887
  seen.add(key);
20941
20888
  });
20942
20889
  });
20943
- var RefFields = {
20890
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20891
+ var AttachmentFields = {
20944
20892
  addonId: string(),
20945
- stableId: string()
20893
+ stableId: string(),
20894
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20946
20895
  };
20947
20896
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20948
20897
  object({
20949
- ...RefFields,
20898
+ ...AttachmentFields,
20950
20899
  state: literal("ready"),
20951
20900
  deviceId: number(),
20952
20901
  name: string(),
20953
20902
  caps: array(string()).readonly()
20954
20903
  }),
20955
20904
  object({
20956
- ...RefFields,
20905
+ ...AttachmentFields,
20957
20906
  state: literal("offline"),
20958
20907
  deviceId: number(),
20959
20908
  name: string(),
20960
20909
  reason: _enum(["offline", "disabled"])
20961
20910
  }),
20962
20911
  object({
20963
- ...RefFields,
20912
+ ...AttachmentFields,
20964
20913
  state: literal("missing"),
20965
20914
  reason: string()
20966
20915
  }),
20967
20916
  object({
20968
- ...RefFields,
20917
+ ...AttachmentFields,
20969
20918
  state: literal("unsupported"),
20970
20919
  deviceId: number(),
20971
20920
  name: string(),
20972
20921
  reason: string()
20973
20922
  }),
20974
20923
  object({
20975
- ...RefFields,
20924
+ ...AttachmentFields,
20976
20925
  state: literal("unreadable"),
20977
20926
  reason: string()
20978
20927
  })
@@ -20985,17 +20934,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20985
20934
  * say.
20986
20935
  */
20987
20936
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20937
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20938
+ var CameraOwnMotionSchema = _enum([
20939
+ "always",
20940
+ "when-confirmed",
20941
+ "never"
20942
+ ]);
20943
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20944
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20945
+ /**
20946
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20947
+ * never the effective value. The camera's `motion` slice is the effective one,
20948
+ * so a view of the camera's own row reads this.
20949
+ * - `atMs`: when the bridge received the camera's last own edge.
20950
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20951
+ * AND it is younger than the window the bridge counts the camera's own motion
20952
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20953
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20954
+ * within the window; a status read is a snapshot, so a live view re-asks.
20955
+ * Absent = this orchestrator has not received the camera's own motion since it
20956
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20957
+ */
20958
+ var CameraRawLevelSchema = object({
20959
+ detected: boolean(),
20960
+ atMs: number()
20961
+ });
20988
20962
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
20989
- object({ state: literal("not-configured") }),
20963
+ object({
20964
+ state: literal("not-configured"),
20965
+ cameraLevel: CameraRawLevelSchema.optional()
20966
+ }),
20990
20967
  object({
20991
20968
  state: literal("unreadable"),
20992
- reason: string()
20969
+ reason: string(),
20970
+ cameraLevel: CameraRawLevelSchema.optional()
20993
20971
  }),
20994
20972
  object({
20995
20973
  state: literal("configured"),
20996
- mode: CameraSensorsModeSchema,
20974
+ cameraLevel: CameraRawLevelSchema.optional(),
20997
20975
  sensors: array(CameraSensorAttachmentSchema).readonly(),
20998
- notForwarded: CameraSensorsNotForwardedSchema.optional()
20976
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
20977
+ cameraMotion: CameraOwnMotionSchema.optional(),
20978
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
20979
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
20999
20980
  })
21000
20981
  ]);
21001
20982
  Object.freeze({
@@ -21680,14 +21661,14 @@ var TrackSchema = object({
21680
21661
  * `derive-returned-null tile=standin`,
21681
21662
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
21682
21663
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
21683
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
21664
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
21684
21665
  * tile is a face/plate stand-in, a raster crop, or an icon.
21685
21666
  *
21686
21667
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
21687
21668
  * the TILE ranked below native, so a track whose thumbnail landed natively
21688
21669
  * while its key frame missed carried no reason at all — three of the four
21689
21670
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
21690
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
21671
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
21691
21672
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
21692
21673
  * lastFrame copy source`), so its absence is now on this line whatever the
21693
21674
  * tile ended up being.
@@ -21774,7 +21755,7 @@ var MotionEventSchema = object({
21774
21755
  /**
21775
21756
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
21776
21757
  * first entry is always `0`) of every genuine off→on transition the
21777
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
21758
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
21778
21759
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
21779
21760
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
21780
21761
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -22298,6 +22279,7 @@ var KeyEventSchema = object({
22298
22279
  bestEventId: string(),
22299
22280
  /** Track lifetime in ms (lastSeen - firstSeen). */
22300
22281
  windowMs: number().optional(),
22282
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
22301
22283
  ...TrackFlagFields,
22302
22284
  ...TrackRetrainFields
22303
22285
  });
@@ -24226,8 +24208,10 @@ var RunnerCameraConfigSchema = object({
24226
24208
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24227
24209
  * analyzer providers) running on decoded frames in this runner.
24228
24210
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24229
- * analytics). The provider emits ProviderMotion
24230
- * events; the orchestrator forwards to `reportMotion`.
24211
+ * analytics). The provider emits its raw push as `ProviderMotion`
24212
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24213
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24214
+ * `reportMotion`.
24231
24215
  */
24232
24216
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24233
24217
  /**
@@ -24404,7 +24388,15 @@ var RunnerLocalLoadSchema = object({
24404
24388
  hasGpu: boolean(),
24405
24389
  inferenceBackend: string().optional(),
24406
24390
  cpuCores: number().optional()
24407
- })
24391
+ }),
24392
+ /**
24393
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24394
+ * runner never writes it. ABSENT = a runner older than D696, which still
24395
+ * writes the slice from its phase machine; the orchestrator does not write
24396
+ * while any runner node is absent-or-unanswered, so one slice never has two
24397
+ * writers.
24398
+ */
24399
+ motionSliceWriter: literal("orchestrator").optional()
24408
24400
  });
24409
24401
  /**
24410
24402
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -27069,7 +27061,7 @@ var ClipPlaybackSchema = object({
27069
27061
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
27070
27062
  * time the camera is awake for its own reasons — is deliberately not a member:
27071
27063
  * it was proposed, it is free on the battery, and the operator declined it on
27072
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
27064
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
27073
27065
  * D558 "Considered and not taken").
27074
27066
  */
27075
27067
  var ClipWakeSchema = _enum(["authorised"]);
@@ -27330,7 +27322,7 @@ DeviceType.Camera, method(object({
27330
27322
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
27331
27323
  * assumed the answer was a fan-out over everything a camera has. The
27332
27324
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
27333
- * solo"* — so the list is asked of one provider at a time and there is
27325
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
27334
27326
  * nothing to filter out of it.
27335
27327
  */
27336
27328
  provider: string().min(1)
@@ -29933,6 +29925,70 @@ onStatusChanged: { data: object({
29933
29925
  * whether persisting is worth a SQLite commit. */
29934
29926
  volatileStateFields: ["lastChangedAt"]
29935
29927
  };
29928
+ var DoorbellStatusSchema = object({
29929
+ /** Ms epoch of the last press. null = never observed since this provider started. */
29930
+ lastPressedAt: number().nullable(),
29931
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
29932
+ pressCountSinceStart: number()
29933
+ });
29934
+ var DoorbellPressEventSchema = object({
29935
+ deviceId: number(),
29936
+ timestamp: number()
29937
+ });
29938
+ /**
29939
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
29940
+ * they are the same cap:
29941
+ *
29942
+ * - **Native** providers, registered per device by a driver addon through
29943
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
29944
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
29945
+ * camera level). They emit `onPressed` on every firmware ring.
29946
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
29947
+ * the cap, its `lastPressedAt` rising from the sources the operator
29948
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
29949
+ * from that field's advance (`fromState`).
29950
+ *
29951
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
29952
+ */
29953
+ var doorbellCapability = {
29954
+ name: "doorbell",
29955
+ scope: "device",
29956
+ deviceNative: true,
29957
+ mode: "singleton",
29958
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
29959
+ methods: {},
29960
+ events: {
29961
+ /**
29962
+ * Fires once per physical press. Reolink delivers via Baichuan
29963
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
29964
+ * release/duration — it's a pulse.
29965
+ */
29966
+ onPressed: {
29967
+ data: DoorbellPressEventSchema,
29968
+ fromState: {
29969
+ field: "lastPressedAt",
29970
+ on: "advance"
29971
+ }
29972
+ } },
29973
+ status: {
29974
+ schema: DoorbellStatusSchema,
29975
+ kind: "push"
29976
+ },
29977
+ /**
29978
+ * Runtime-state slice — last press timestamp + lifetime press count.
29979
+ * Mirrored by the kernel and readable via
29980
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
29981
+ * without subscribing.
29982
+ */
29983
+ runtimeState: DoorbellStatusSchema,
29984
+ /**
29985
+ * Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
29986
+ *
29987
+ * See `RuntimeStateDurability`. Enforced by
29988
+ * `scripts/check-runtime-state-durability.ts`.
29989
+ */
29990
+ durability: "restored"
29991
+ };
29936
29992
  /**
29937
29993
  * Enum-state sensor — a string value picked from a finite option set.
29938
29994
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -32077,9 +32133,9 @@ var MotionStatusSchema = object({
32077
32133
  /** Ms epoch of the last detected-true observation. Null if never detected. */
32078
32134
  lastDetectedAt: number().nullable(),
32079
32135
  /**
32080
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
32081
- * `null` while false and on every `Sensor` device (D475) — see that
32082
- * constant's doc for the one-authority rule.
32136
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
32137
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
32138
+ * device (D475) — see that constant's doc for the one-authority rule.
32083
32139
  *
32084
32140
  * ## Reading this field still arms nothing
32085
32141
  *
@@ -32097,34 +32153,31 @@ var MotionStatusSchema = object({
32097
32153
  * `addon-export-alexa/src/motion-clear-hold.ts` and
32098
32154
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
32099
32155
  *
32100
- * ## Who writes it
32101
- *
32102
- * - **Cameras** — the runner's phase machine, `active → watching` on
32103
- * `cooldown_expired`, which then writes this slice with
32104
- * `detected: false` (`handlePhaseChanged` in
32105
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
32106
- * matters most for the sources that only ever push a rising one:
32107
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
32108
- * a false.
32109
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
32110
- * provider pushes the false itself, from the upstream system's own
32111
- * state change. No phase machine is involved.
32112
- *
32113
- * ### The phase machine is CANONICAL, not sole — and that is a defect
32114
- *
32115
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
32116
- * phase machine is the sole writer for a camera. It is not.
32117
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
32118
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
32119
- * Hikvision's comment says why: it read THIS docblock, agreed the
32120
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
32121
- * two authorities can disagree about one slice, which this repo
32122
- * forbids, and the doc said otherwise — which is worse than saying
32123
- * nothing, because it reads as verification.
32124
- *
32125
- * This predates D475 and is not fixed there: the fix touches every
32126
- * camera provider. Recorded in D475's Consequences. Do not restore the
32127
- * "sole writer" wording without also removing the other writers.
32156
+ * ## Who writes it (D696)
32157
+ *
32158
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
32159
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
32160
+ * `camera-sensors/motion-slice.ts`), alongside the effective
32161
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
32162
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
32163
+ * device activity, as the camera's `motionSources` counts them. A source
32164
+ * that never sends a clear falls one window after its last `true`.
32165
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
32166
+ * writes this slice (not even a boot seed), and neither does the runner's
32167
+ * phase machine: its phase is "a session is attached" for every on-motion
32168
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
32169
+ * A provider's `isDetected` answers from the hub's slice.
32170
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32171
+ * imports) — the provider pushes both edges itself, from the upstream
32172
+ * system's own state change. That is the sensor's own fact.
32173
+ *
32174
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
32175
+ * `motion` slice; each sensor writer is a named exemption.
32176
+ *
32177
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
32178
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
32179
+ * it, every provider seeded it at boot, and every session left it
32180
+ * `detected: true` after its detach.
32128
32181
  */
32129
32182
  autoClearAfterMs: number().nullable()
32130
32183
  });
@@ -32196,11 +32249,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
32196
32249
  */
32197
32250
  runtimeState: MotionStatusSchema,
32198
32251
  /**
32199
- * Runtime-state durability: **session** — every writer of this slice
32252
+ * Runtime-state durability: **session** — the writer of this slice
32200
32253
  * writes only on an EDGE, so a restored `detected: true` would stay
32201
32254
  * frozen until the next one instead of being corrected. The next edge
32202
- * re-publishes the real state. (On who the writers are, and why there
32203
- * is more than one, see `autoClearAfterMs` above.)
32255
+ * re-publishes the real state, and the orchestrator re-publishes every
32256
+ * camera when it starts writing (D696; on who writes it, see
32257
+ * `autoClearAfterMs` above).
32204
32258
  *
32205
32259
  * See `RuntimeStateDurability`. Enforced by
32206
32260
  * `scripts/check-runtime-state-durability.ts`.
@@ -34583,8 +34637,7 @@ var ptzAutotrackCapability = {
34583
34637
  deviceNative: true,
34584
34638
  mode: "singleton",
34585
34639
  /**
34586
- * Two kinds of provider behind one name, the same shape `snapshot` and
34587
- * `doorbell` use:
34640
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
34588
34641
  *
34589
34642
  * - **Native**: the camera's own firmware autotrack, registered per device by
34590
34643
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -34592,7 +34645,7 @@ var ptzAutotrackCapability = {
34592
34645
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
34593
34646
  * which follows a subject with `ptz.move` pulses driven by the detection
34594
34647
  * pipeline. `defaultActive: false` — the operator binds it per camera in
34595
- * the bindings UI, exactly as `virtual-doorbell` is bound.
34648
+ * the bindings UI.
34596
34649
  *
34597
34650
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
34598
34651
  * one switch for the function either way. A camera never has both driving its
@@ -35267,7 +35320,7 @@ var ReadGopBytesResultSchema = object({
35267
35320
  /**
35268
35321
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
35269
35322
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
35270
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
35323
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
35271
35324
  * a replay needs several seconds of native pixels, not one frame.
35272
35325
  *
35273
35326
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -38631,6 +38684,7 @@ var zoneRulesCapability = {
38631
38684
  */
38632
38685
  durability: "restored"
38633
38686
  };
38687
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
38634
38688
  /**
38635
38689
  * Accessory device helpers — shared across drivers.
38636
38690
  *
@@ -39690,13 +39744,14 @@ var BaseDeviceProvider = class extends BaseAddon {
39690
39744
  async getStatus() {
39691
39745
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
39692
39746
  const summary = this.restoreFailureSummary();
39693
- if (summary === null) return {
39747
+ const base = {
39694
39748
  connected: true,
39695
- deviceCount: all.length
39749
+ deviceCount: all.length,
39750
+ motionSliceWriter: "orchestrator"
39696
39751
  };
39752
+ if (summary === null) return base;
39697
39753
  return {
39698
- connected: true,
39699
- deviceCount: all.length,
39754
+ ...base,
39700
39755
  error: summary
39701
39756
  };
39702
39757
  }
@@ -45132,6 +45187,12 @@ Object.freeze({
45132
45187
  addonId: null,
45133
45188
  access: "view"
45134
45189
  },
45190
+ "notificationRules.getAlarmSensors": {
45191
+ capName: "notification-rules",
45192
+ capScope: "system",
45193
+ addonId: null,
45194
+ access: "view"
45195
+ },
45135
45196
  "notificationRules.getClipRetentionAsks": {
45136
45197
  capName: "notification-rules",
45137
45198
  capScope: "system",
@@ -48710,6 +48771,11 @@ Object.freeze({
48710
48771
  }
48711
48772
  });
48712
48773
  Object.freeze({
48774
+ "accessories.getStatus": [{
48775
+ name: "deviceId",
48776
+ form: "single",
48777
+ optional: false
48778
+ }],
48713
48779
  "accessories.setChildHidden": [{
48714
48780
  name: "childDeviceId",
48715
48781
  form: "single",
@@ -48729,6 +48795,11 @@ Object.freeze({
48729
48795
  form: "single",
48730
48796
  optional: false
48731
48797
  }],
48798
+ "airQualitySensor.getStatus": [{
48799
+ name: "deviceId",
48800
+ form: "single",
48801
+ optional: false
48802
+ }],
48732
48803
  "alarmPanel.arm": [{
48733
48804
  name: "deviceId",
48734
48805
  form: "single",
@@ -48739,11 +48810,36 @@ Object.freeze({
48739
48810
  form: "single",
48740
48811
  optional: false
48741
48812
  }],
48813
+ "alarmPanel.getStatus": [{
48814
+ name: "deviceId",
48815
+ form: "single",
48816
+ optional: false
48817
+ }],
48742
48818
  "alarmPanel.trigger": [{
48743
48819
  name: "deviceId",
48744
48820
  form: "single",
48745
48821
  optional: false
48746
48822
  }],
48823
+ "ambientLightSensor.getStatus": [{
48824
+ name: "deviceId",
48825
+ form: "single",
48826
+ optional: false
48827
+ }],
48828
+ "audioAnalysis.applyDeviceSettingsPatch": [{
48829
+ name: "deviceId",
48830
+ form: "single",
48831
+ optional: false
48832
+ }],
48833
+ "audioAnalysis.getDeviceLiveContribution": [{
48834
+ name: "deviceId",
48835
+ form: "single",
48836
+ optional: false
48837
+ }],
48838
+ "audioAnalysis.getDeviceSettingsContribution": [{
48839
+ name: "deviceId",
48840
+ form: "single",
48841
+ optional: false
48842
+ }],
48747
48843
  "audioAnalysis.resolveDeviceSettings": [{
48748
48844
  name: "deviceId",
48749
48845
  form: "single",
@@ -48784,16 +48880,36 @@ Object.freeze({
48784
48880
  form: "single",
48785
48881
  optional: false
48786
48882
  }],
48883
+ "automationControl.getStatus": [{
48884
+ name: "deviceId",
48885
+ form: "single",
48886
+ optional: false
48887
+ }],
48787
48888
  "automationControl.trigger": [{
48788
48889
  name: "deviceId",
48789
48890
  form: "single",
48790
48891
  optional: false
48791
48892
  }],
48893
+ "battery.getStatus": [{
48894
+ name: "deviceId",
48895
+ form: "single",
48896
+ optional: false
48897
+ }],
48792
48898
  "battery.wakeForStream": [{
48793
48899
  name: "deviceId",
48794
48900
  form: "single",
48795
48901
  optional: false
48796
48902
  }],
48903
+ "binary.getStatus": [{
48904
+ name: "deviceId",
48905
+ form: "single",
48906
+ optional: false
48907
+ }],
48908
+ "brightness.getStatus": [{
48909
+ name: "deviceId",
48910
+ form: "single",
48911
+ optional: false
48912
+ }],
48797
48913
  "brightness.setBrightness": [{
48798
48914
  name: "deviceId",
48799
48915
  form: "single",
@@ -48809,6 +48925,26 @@ Object.freeze({
48809
48925
  form: "single",
48810
48926
  optional: false
48811
48927
  }],
48928
+ "cameraCredentials.getStatus": [{
48929
+ name: "deviceId",
48930
+ form: "single",
48931
+ optional: false
48932
+ }],
48933
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
48934
+ name: "deviceId",
48935
+ form: "single",
48936
+ optional: false
48937
+ }],
48938
+ "cameraGridLayout.getDeviceLiveContribution": [{
48939
+ name: "deviceId",
48940
+ form: "single",
48941
+ optional: false
48942
+ }],
48943
+ "cameraGridLayout.getDeviceSettingsContribution": [{
48944
+ name: "deviceId",
48945
+ form: "single",
48946
+ optional: false
48947
+ }],
48812
48948
  "cameraGridLayout.getLayout": [{
48813
48949
  name: "deviceId",
48814
48950
  form: "single",
@@ -48824,6 +48960,21 @@ Object.freeze({
48824
48960
  form: "single",
48825
48961
  optional: false
48826
48962
  }],
48963
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
48964
+ name: "deviceId",
48965
+ form: "single",
48966
+ optional: false
48967
+ }],
48968
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
48969
+ name: "deviceId",
48970
+ form: "single",
48971
+ optional: false
48972
+ }],
48973
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
48974
+ name: "deviceId",
48975
+ form: "single",
48976
+ optional: false
48977
+ }],
48827
48978
  "cameraStreams.getBrokerStreams": [{
48828
48979
  name: "deviceId",
48829
48980
  form: "single",
@@ -48849,6 +49000,16 @@ Object.freeze({
48849
49000
  form: "single",
48850
49001
  optional: false
48851
49002
  }],
49003
+ "carbonMonoxide.getStatus": [{
49004
+ name: "deviceId",
49005
+ form: "single",
49006
+ optional: false
49007
+ }],
49008
+ "climateControl.getStatus": [{
49009
+ name: "deviceId",
49010
+ form: "single",
49011
+ optional: false
49012
+ }],
48852
49013
  "climateControl.setFanMode": [{
48853
49014
  name: "deviceId",
48854
49015
  form: "single",
@@ -48889,16 +49050,41 @@ Object.freeze({
48889
49050
  form: "single",
48890
49051
  optional: false
48891
49052
  }],
49053
+ "color.getStatus": [{
49054
+ name: "deviceId",
49055
+ form: "single",
49056
+ optional: false
49057
+ }],
48892
49058
  "color.setColor": [{
48893
49059
  name: "deviceId",
48894
49060
  form: "single",
48895
49061
  optional: false
48896
49062
  }],
49063
+ "connectivity.getStatus": [{
49064
+ name: "deviceId",
49065
+ form: "single",
49066
+ optional: false
49067
+ }],
49068
+ "consumables.getStatus": [{
49069
+ name: "deviceId",
49070
+ form: "single",
49071
+ optional: false
49072
+ }],
48897
49073
  "consumables.reset": [{
48898
49074
  name: "deviceId",
48899
49075
  form: "single",
48900
49076
  optional: false
48901
49077
  }],
49078
+ "contact.getStatus": [{
49079
+ name: "deviceId",
49080
+ form: "single",
49081
+ optional: false
49082
+ }],
49083
+ "control.getStatus": [{
49084
+ name: "deviceId",
49085
+ form: "single",
49086
+ optional: false
49087
+ }],
48902
49088
  "control.setValue": [{
48903
49089
  name: "deviceId",
48904
49090
  form: "single",
@@ -48909,6 +49095,11 @@ Object.freeze({
48909
49095
  form: "single",
48910
49096
  optional: false
48911
49097
  }],
49098
+ "cover.getStatus": [{
49099
+ name: "deviceId",
49100
+ form: "single",
49101
+ optional: false
49102
+ }],
48912
49103
  "cover.open": [{
48913
49104
  name: "deviceId",
48914
49105
  form: "single",
@@ -48934,6 +49125,11 @@ Object.freeze({
48934
49125
  form: "single",
48935
49126
  optional: false
48936
49127
  }],
49128
+ "dayNight.getStatus": [{
49129
+ name: "deviceId",
49130
+ form: "single",
49131
+ optional: false
49132
+ }],
48937
49133
  "dayNight.setSettings": [{
48938
49134
  name: "deviceId",
48939
49135
  form: "single",
@@ -48944,11 +49140,31 @@ Object.freeze({
48944
49140
  form: "single",
48945
49141
  optional: true
48946
49142
  }],
49143
+ "detectionPipeline.applyDeviceSettingsPatch": [{
49144
+ name: "deviceId",
49145
+ form: "single",
49146
+ optional: false
49147
+ }],
49148
+ "detectionPipeline.getDeviceLiveContribution": [{
49149
+ name: "deviceId",
49150
+ form: "single",
49151
+ optional: false
49152
+ }],
49153
+ "detectionPipeline.getDeviceSettingsContribution": [{
49154
+ name: "deviceId",
49155
+ form: "single",
49156
+ optional: false
49157
+ }],
48947
49158
  "deviceAdminLink.getAdminLink": [{
48948
49159
  name: "deviceId",
48949
49160
  form: "single",
48950
49161
  optional: false
48951
49162
  }],
49163
+ "deviceAdoption.getStatus": [{
49164
+ name: "deviceId",
49165
+ form: "single",
49166
+ optional: false
49167
+ }],
48952
49168
  "deviceAdoption.release": [{
48953
49169
  name: "camDeviceId",
48954
49170
  form: "single",
@@ -48964,6 +49180,11 @@ Object.freeze({
48964
49180
  form: "single",
48965
49181
  optional: false
48966
49182
  }],
49183
+ "deviceDiscovery.getStatus": [{
49184
+ name: "deviceId",
49185
+ form: "single",
49186
+ optional: false
49187
+ }],
48967
49188
  "deviceDiscovery.listDiscovered": [{
48968
49189
  name: "deviceId",
48969
49190
  form: "single",
@@ -48983,6 +49204,21 @@ Object.freeze({
48983
49204
  form: "single",
48984
49205
  optional: false
48985
49206
  }],
49207
+ "deviceExport.applyDeviceSettingsPatch": [{
49208
+ name: "deviceId",
49209
+ form: "single",
49210
+ optional: false
49211
+ }],
49212
+ "deviceExport.getDeviceLiveContribution": [{
49213
+ name: "deviceId",
49214
+ form: "single",
49215
+ optional: false
49216
+ }],
49217
+ "deviceExport.getDeviceSettingsContribution": [{
49218
+ name: "deviceId",
49219
+ form: "single",
49220
+ optional: false
49221
+ }],
48986
49222
  "deviceExtension.listCandidates": [{
48987
49223
  name: "deviceId",
48988
49224
  form: "single",
@@ -49331,6 +49567,26 @@ Object.freeze({
49331
49567
  form: "single",
49332
49568
  optional: false
49333
49569
  }],
49570
+ "deviceStatus.getStatus": [{
49571
+ name: "deviceId",
49572
+ form: "single",
49573
+ optional: false
49574
+ }],
49575
+ "doorbell.getStatus": [{
49576
+ name: "deviceId",
49577
+ form: "single",
49578
+ optional: false
49579
+ }],
49580
+ "enumSensor.getStatus": [{
49581
+ name: "deviceId",
49582
+ form: "single",
49583
+ optional: false
49584
+ }],
49585
+ "eventEmitter.getStatus": [{
49586
+ name: "deviceId",
49587
+ form: "single",
49588
+ optional: false
49589
+ }],
49334
49590
  "faceGallery.getFaceByTrack": [{
49335
49591
  name: "deviceId",
49336
49592
  form: "single",
@@ -49345,6 +49601,11 @@ Object.freeze({
49345
49601
  form: "array",
49346
49602
  optional: true
49347
49603
  }],
49604
+ "fanControl.getStatus": [{
49605
+ name: "deviceId",
49606
+ form: "single",
49607
+ optional: false
49608
+ }],
49348
49609
  "fanControl.setDirection": [{
49349
49610
  name: "deviceId",
49350
49611
  form: "single",
@@ -49365,6 +49626,26 @@ Object.freeze({
49365
49626
  form: "single",
49366
49627
  optional: false
49367
49628
  }],
49629
+ "featureProbe.getStatus": [{
49630
+ name: "deviceId",
49631
+ form: "single",
49632
+ optional: false
49633
+ }],
49634
+ "flood.getStatus": [{
49635
+ name: "deviceId",
49636
+ form: "single",
49637
+ optional: false
49638
+ }],
49639
+ "gas.getStatus": [{
49640
+ name: "deviceId",
49641
+ form: "single",
49642
+ optional: false
49643
+ }],
49644
+ "humidifier.getStatus": [{
49645
+ name: "deviceId",
49646
+ form: "single",
49647
+ optional: false
49648
+ }],
49368
49649
  "humidifier.setMode": [{
49369
49650
  name: "deviceId",
49370
49651
  form: "single",
@@ -49380,11 +49661,26 @@ Object.freeze({
49380
49661
  form: "single",
49381
49662
  optional: false
49382
49663
  }],
49664
+ "humiditySensor.getStatus": [{
49665
+ name: "deviceId",
49666
+ form: "single",
49667
+ optional: false
49668
+ }],
49669
+ "image.getStatus": [{
49670
+ name: "deviceId",
49671
+ form: "single",
49672
+ optional: false
49673
+ }],
49383
49674
  "imageSettings.getOptions": [{
49384
49675
  name: "deviceId",
49385
49676
  form: "single",
49386
49677
  optional: false
49387
49678
  }],
49679
+ "imageSettings.getStatus": [{
49680
+ name: "deviceId",
49681
+ form: "single",
49682
+ optional: false
49683
+ }],
49388
49684
  "imageSettings.setSettings": [{
49389
49685
  name: "deviceId",
49390
49686
  form: "single",
@@ -49395,6 +49691,11 @@ Object.freeze({
49395
49691
  form: "single",
49396
49692
  optional: false
49397
49693
  }],
49694
+ "intercom.getStatus": [{
49695
+ name: "deviceId",
49696
+ form: "single",
49697
+ optional: false
49698
+ }],
49398
49699
  "intercom.handleAnswer": [{
49399
49700
  name: "deviceId",
49400
49701
  form: "single",
@@ -49425,6 +49726,11 @@ Object.freeze({
49425
49726
  form: "single",
49426
49727
  optional: false
49427
49728
  }],
49729
+ "lawnMowerControl.getStatus": [{
49730
+ name: "deviceId",
49731
+ form: "single",
49732
+ optional: false
49733
+ }],
49428
49734
  "lawnMowerControl.pause": [{
49429
49735
  name: "deviceId",
49430
49736
  form: "single",
@@ -49435,6 +49741,11 @@ Object.freeze({
49435
49741
  form: "single",
49436
49742
  optional: false
49437
49743
  }],
49744
+ "lockControl.getStatus": [{
49745
+ name: "deviceId",
49746
+ form: "single",
49747
+ optional: false
49748
+ }],
49438
49749
  "lockControl.lock": [{
49439
49750
  name: "deviceId",
49440
49751
  form: "single",
@@ -49450,6 +49761,11 @@ Object.freeze({
49450
49761
  form: "single",
49451
49762
  optional: false
49452
49763
  }],
49764
+ "mediaPlayer.getStatus": [{
49765
+ name: "deviceId",
49766
+ form: "single",
49767
+ optional: false
49768
+ }],
49453
49769
  "mediaPlayer.next": [{
49454
49770
  name: "deviceId",
49455
49771
  form: "single",
@@ -49510,6 +49826,11 @@ Object.freeze({
49510
49826
  form: "single",
49511
49827
  optional: false
49512
49828
  }],
49829
+ "motion.getStatus": [{
49830
+ name: "deviceId",
49831
+ form: "single",
49832
+ optional: false
49833
+ }],
49513
49834
  "motion.isDetected": [{
49514
49835
  name: "deviceId",
49515
49836
  form: "single",
@@ -49520,11 +49841,31 @@ Object.freeze({
49520
49841
  form: "single",
49521
49842
  optional: false
49522
49843
  }],
49844
+ "motionDetection.applyDeviceSettingsPatch": [{
49845
+ name: "deviceId",
49846
+ form: "single",
49847
+ optional: false
49848
+ }],
49849
+ "motionDetection.getDeviceLiveContribution": [{
49850
+ name: "deviceId",
49851
+ form: "single",
49852
+ optional: false
49853
+ }],
49854
+ "motionDetection.getDeviceSettingsContribution": [{
49855
+ name: "deviceId",
49856
+ form: "single",
49857
+ optional: false
49858
+ }],
49523
49859
  "motionDetection.removeCamera": [{
49524
49860
  name: "deviceId",
49525
49861
  form: "single",
49526
49862
  optional: false
49527
49863
  }],
49864
+ "motionTrigger.getStatus": [{
49865
+ name: "deviceId",
49866
+ form: "single",
49867
+ optional: false
49868
+ }],
49528
49869
  "motionTrigger.setMotionTrigger": [{
49529
49870
  name: "deviceId",
49530
49871
  form: "single",
@@ -49535,6 +49876,11 @@ Object.freeze({
49535
49876
  form: "single",
49536
49877
  optional: false
49537
49878
  }],
49879
+ "motionZones.getStatus": [{
49880
+ name: "deviceId",
49881
+ form: "single",
49882
+ optional: false
49883
+ }],
49538
49884
  "motionZones.setZone": [{
49539
49885
  name: "deviceId",
49540
49886
  form: "single",
@@ -49545,6 +49891,11 @@ Object.freeze({
49545
49891
  form: "single",
49546
49892
  optional: false
49547
49893
  }],
49894
+ "nativeObjectDetection.getStatus": [{
49895
+ name: "deviceId",
49896
+ form: "single",
49897
+ optional: false
49898
+ }],
49548
49899
  "nativeObjectDetection.setEnabled": [{
49549
49900
  name: "deviceId",
49550
49901
  form: "single",
@@ -49560,6 +49911,11 @@ Object.freeze({
49560
49911
  form: "single",
49561
49912
  optional: false
49562
49913
  }],
49914
+ "navigation.getStatus": [{
49915
+ name: "deviceId",
49916
+ form: "single",
49917
+ optional: false
49918
+ }],
49563
49919
  "navigation.goToPoint": [{
49564
49920
  name: "deviceId",
49565
49921
  form: "single",
@@ -49605,6 +49961,11 @@ Object.freeze({
49605
49961
  form: "single",
49606
49962
  optional: false
49607
49963
  }],
49964
+ "networkLink.getStatus": [{
49965
+ name: "deviceId",
49966
+ form: "single",
49967
+ optional: false
49968
+ }],
49608
49969
  "networkQuality.getDeviceStats": [{
49609
49970
  name: "deviceId",
49610
49971
  form: "single",
@@ -49615,6 +49976,11 @@ Object.freeze({
49615
49976
  form: "single",
49616
49977
  optional: false
49617
49978
  }],
49979
+ "notificationRules.getAlarmSensors": [{
49980
+ name: "deviceIds",
49981
+ form: "array",
49982
+ optional: false
49983
+ }],
49618
49984
  "notificationRules.setDeviceMuted": [{
49619
49985
  name: "deviceId",
49620
49986
  form: "single",
@@ -49625,11 +49991,26 @@ Object.freeze({
49625
49991
  form: "single",
49626
49992
  optional: false
49627
49993
  }],
49994
+ "notifier.getStatus": [{
49995
+ name: "deviceId",
49996
+ form: "single",
49997
+ optional: false
49998
+ }],
49628
49999
  "notifier.send": [{
49629
50000
  name: "deviceId",
49630
50001
  form: "single",
49631
50002
  optional: false
49632
50003
  }],
50004
+ "numericSensor.getStatus": [{
50005
+ name: "deviceId",
50006
+ form: "single",
50007
+ optional: false
50008
+ }],
50009
+ "osd.getStatus": [{
50010
+ name: "deviceId",
50011
+ form: "single",
50012
+ optional: false
50013
+ }],
49633
50014
  "osd.setOverlay": [{
49634
50015
  name: "deviceId",
49635
50016
  form: "single",
@@ -49689,6 +50070,11 @@ Object.freeze({
49689
50070
  form: "single",
49690
50071
  optional: false
49691
50072
  }],
50073
+ "petFeeder.getStatus": [{
50074
+ name: "deviceId",
50075
+ form: "single",
50076
+ optional: false
50077
+ }],
49692
50078
  "petFeeder.markFoodReplenished": [{
49693
50079
  name: "deviceId",
49694
50080
  form: "single",
@@ -49724,6 +50110,11 @@ Object.freeze({
49724
50110
  form: "single",
49725
50111
  optional: false
49726
50112
  }],
50113
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
50114
+ name: "deviceId",
50115
+ form: "single",
50116
+ optional: false
50117
+ }],
49727
50118
  "pipelineAnalytics.clearTrackRelation": [{
49728
50119
  name: "deviceId",
49729
50120
  form: "single",
@@ -49764,6 +50155,16 @@ Object.freeze({
49764
50155
  form: "single",
49765
50156
  optional: false
49766
50157
  }],
50158
+ "pipelineAnalytics.getDeviceLiveContribution": [{
50159
+ name: "deviceId",
50160
+ form: "single",
50161
+ optional: false
50162
+ }],
50163
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
50164
+ name: "deviceId",
50165
+ form: "single",
50166
+ optional: false
50167
+ }],
49767
50168
  "pipelineAnalytics.getEventDensity": [{
49768
50169
  name: "deviceId",
49769
50170
  form: "single",
@@ -49979,6 +50380,11 @@ Object.freeze({
49979
50380
  form: "single",
49980
50381
  optional: true
49981
50382
  }],
50383
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
50384
+ name: "deviceId",
50385
+ form: "single",
50386
+ optional: false
50387
+ }],
49982
50388
  "pipelineOrchestrator.assignAudio": [{
49983
50389
  name: "deviceId",
49984
50390
  form: "single",
@@ -50024,6 +50430,16 @@ Object.freeze({
50024
50430
  form: "single",
50025
50431
  optional: false
50026
50432
  }],
50433
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
50434
+ name: "deviceId",
50435
+ form: "single",
50436
+ optional: false
50437
+ }],
50438
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
50439
+ name: "deviceId",
50440
+ form: "single",
50441
+ optional: false
50442
+ }],
50027
50443
  "pipelineOrchestrator.getPipelineAssignment": [{
50028
50444
  name: "deviceId",
50029
50445
  form: "single",
@@ -50144,11 +50560,31 @@ Object.freeze({
50144
50560
  form: "single",
50145
50561
  optional: true
50146
50562
  }],
50563
+ "powerMeter.getStatus": [{
50564
+ name: "deviceId",
50565
+ form: "single",
50566
+ optional: false
50567
+ }],
50568
+ "presence.getStatus": [{
50569
+ name: "deviceId",
50570
+ form: "single",
50571
+ optional: false
50572
+ }],
50573
+ "pressureSensor.getStatus": [{
50574
+ name: "deviceId",
50575
+ form: "single",
50576
+ optional: false
50577
+ }],
50147
50578
  "privacyMask.getOptions": [{
50148
50579
  name: "deviceId",
50149
50580
  form: "single",
50150
50581
  optional: false
50151
50582
  }],
50583
+ "privacyMask.getStatus": [{
50584
+ name: "deviceId",
50585
+ form: "single",
50586
+ optional: false
50587
+ }],
50152
50588
  "privacyMask.setAudioEnabled": [{
50153
50589
  name: "deviceId",
50154
50590
  form: "single",
@@ -50199,6 +50635,11 @@ Object.freeze({
50199
50635
  form: "single",
50200
50636
  optional: false
50201
50637
  }],
50638
+ "ptz.getStatus": [{
50639
+ name: "deviceId",
50640
+ form: "single",
50641
+ optional: false
50642
+ }],
50202
50643
  "ptz.goHome": [{
50203
50644
  name: "deviceId",
50204
50645
  form: "single",
@@ -50289,6 +50730,11 @@ Object.freeze({
50289
50730
  form: "single",
50290
50731
  optional: false
50291
50732
  }],
50733
+ "recordingArchive.applyDeviceSettingsPatch": [{
50734
+ name: "deviceId",
50735
+ form: "single",
50736
+ optional: false
50737
+ }],
50292
50738
  "recordingArchive.deleteFootprint": [{
50293
50739
  name: "deviceId",
50294
50740
  form: "single",
@@ -50309,6 +50755,21 @@ Object.freeze({
50309
50755
  form: "single",
50310
50756
  optional: false
50311
50757
  }],
50758
+ "recordingArchive.getDeviceLiveContribution": [{
50759
+ name: "deviceId",
50760
+ form: "single",
50761
+ optional: false
50762
+ }],
50763
+ "recordingArchive.getDeviceSettingsContribution": [{
50764
+ name: "deviceId",
50765
+ form: "single",
50766
+ optional: false
50767
+ }],
50768
+ "recordingArchive.getStatus": [{
50769
+ name: "deviceId",
50770
+ form: "single",
50771
+ optional: false
50772
+ }],
50312
50773
  "recordingArchive.listOpsLog": [{
50313
50774
  name: "deviceId",
50314
50775
  form: "single",
@@ -50394,6 +50855,11 @@ Object.freeze({
50394
50855
  form: "single",
50395
50856
  optional: false
50396
50857
  }],
50858
+ "recordingOnboard.getStatus": [{
50859
+ name: "deviceId",
50860
+ form: "single",
50861
+ optional: false
50862
+ }],
50397
50863
  "recordingOnboard.setSettings": [{
50398
50864
  name: "deviceId",
50399
50865
  form: "single",
@@ -50424,6 +50890,11 @@ Object.freeze({
50424
50890
  form: "single",
50425
50891
  optional: false
50426
50892
  }],
50893
+ "sceneMonitor.getStatus": [{
50894
+ name: "deviceId",
50895
+ form: "single",
50896
+ optional: false
50897
+ }],
50427
50898
  "sceneMonitor.listScenes": [{
50428
50899
  name: "deviceId",
50429
50900
  form: "single",
@@ -50449,6 +50920,11 @@ Object.freeze({
50449
50920
  form: "single",
50450
50921
  optional: false
50451
50922
  }],
50923
+ "scriptRunner.getStatus": [{
50924
+ name: "deviceId",
50925
+ form: "single",
50926
+ optional: false
50927
+ }],
50452
50928
  "scriptRunner.run": [{
50453
50929
  name: "deviceId",
50454
50930
  form: "single",
@@ -50459,11 +50935,31 @@ Object.freeze({
50459
50935
  form: "single",
50460
50936
  optional: false
50461
50937
  }],
50938
+ "smoke.getStatus": [{
50939
+ name: "deviceId",
50940
+ form: "single",
50941
+ optional: false
50942
+ }],
50943
+ "snapshot.applyDeviceSettingsPatch": [{
50944
+ name: "deviceId",
50945
+ form: "single",
50946
+ optional: false
50947
+ }],
50462
50948
  "snapshot.getDebugState": [{
50463
50949
  name: "deviceId",
50464
50950
  form: "single",
50465
50951
  optional: false
50466
50952
  }],
50953
+ "snapshot.getDeviceLiveContribution": [{
50954
+ name: "deviceId",
50955
+ form: "single",
50956
+ optional: false
50957
+ }],
50958
+ "snapshot.getDeviceSettingsContribution": [{
50959
+ name: "deviceId",
50960
+ form: "single",
50961
+ optional: false
50962
+ }],
50467
50963
  "snapshot.getSnapshot": [{
50468
50964
  name: "deviceId",
50469
50965
  form: "single",
@@ -50480,6 +50976,11 @@ Object.freeze({
50480
50976
  form: "array",
50481
50977
  optional: false
50482
50978
  }],
50979
+ "snapshot.getStatus": [{
50980
+ name: "deviceId",
50981
+ form: "single",
50982
+ optional: false
50983
+ }],
50483
50984
  "snapshot.invalidateCache": [{
50484
50985
  name: "deviceId",
50485
50986
  form: "single",
@@ -50490,6 +50991,11 @@ Object.freeze({
50490
50991
  form: "single",
50491
50992
  optional: false
50492
50993
  }],
50994
+ "streamBroker.applyDeviceSettingsPatch": [{
50995
+ name: "deviceId",
50996
+ form: "single",
50997
+ optional: false
50998
+ }],
50493
50999
  "streamBroker.assignProfile": [{
50494
51000
  name: "deviceId",
50495
51001
  form: "single",
@@ -50505,6 +51011,16 @@ Object.freeze({
50505
51011
  form: "single",
50506
51012
  optional: false
50507
51013
  }],
51014
+ "streamBroker.getDeviceLiveContribution": [{
51015
+ name: "deviceId",
51016
+ form: "single",
51017
+ optional: false
51018
+ }],
51019
+ "streamBroker.getDeviceSettingsContribution": [{
51020
+ name: "deviceId",
51021
+ form: "single",
51022
+ optional: false
51023
+ }],
50508
51024
  "streamBroker.getStreamWithCodec": [{
50509
51025
  name: "deviceId",
50510
51026
  form: "single",
@@ -50565,16 +51081,46 @@ Object.freeze({
50565
51081
  form: "single",
50566
51082
  optional: false
50567
51083
  }],
51084
+ "streamParams.getStatus": [{
51085
+ name: "deviceId",
51086
+ form: "single",
51087
+ optional: false
51088
+ }],
50568
51089
  "streamParams.setProfile": [{
50569
51090
  name: "deviceId",
50570
51091
  form: "single",
50571
51092
  optional: false
50572
51093
  }],
51094
+ "switch.getStatus": [{
51095
+ name: "deviceId",
51096
+ form: "single",
51097
+ optional: false
51098
+ }],
50573
51099
  "switch.setState": [{
50574
51100
  name: "deviceId",
50575
51101
  form: "single",
50576
51102
  optional: false
50577
51103
  }],
51104
+ "tamper.getStatus": [{
51105
+ name: "deviceId",
51106
+ form: "single",
51107
+ optional: false
51108
+ }],
51109
+ "temperatureSensor.getStatus": [{
51110
+ name: "deviceId",
51111
+ form: "single",
51112
+ optional: false
51113
+ }],
51114
+ "update.getStatus": [{
51115
+ name: "deviceId",
51116
+ form: "single",
51117
+ optional: false
51118
+ }],
51119
+ "vacuumControl.getStatus": [{
51120
+ name: "deviceId",
51121
+ form: "single",
51122
+ optional: false
51123
+ }],
50578
51124
  "vacuumControl.locate": [{
50579
51125
  name: "deviceId",
50580
51126
  form: "single",
@@ -50610,6 +51156,11 @@ Object.freeze({
50610
51156
  form: "single",
50611
51157
  optional: false
50612
51158
  }],
51159
+ "valve.getStatus": [{
51160
+ name: "deviceId",
51161
+ form: "single",
51162
+ optional: false
51163
+ }],
50613
51164
  "valve.open": [{
50614
51165
  name: "deviceId",
50615
51166
  form: "single",
@@ -50625,6 +51176,11 @@ Object.freeze({
50625
51176
  form: "single",
50626
51177
  optional: false
50627
51178
  }],
51179
+ "vibration.getStatus": [{
51180
+ name: "deviceId",
51181
+ form: "single",
51182
+ optional: false
51183
+ }],
50628
51184
  "videoclips.dialClipStream": [{
50629
51185
  name: "deviceId",
50630
51186
  form: "single",
@@ -50660,6 +51216,11 @@ Object.freeze({
50660
51216
  form: "single",
50661
51217
  optional: false
50662
51218
  }],
51219
+ "waterHeater.getStatus": [{
51220
+ name: "deviceId",
51221
+ form: "single",
51222
+ optional: false
51223
+ }],
50663
51224
  "waterHeater.setAway": [{
50664
51225
  name: "deviceId",
50665
51226
  form: "single",
@@ -50675,6 +51236,11 @@ Object.freeze({
50675
51236
  form: "single",
50676
51237
  optional: false
50677
51238
  }],
51239
+ "weather.getStatus": [{
51240
+ name: "deviceId",
51241
+ form: "single",
51242
+ optional: false
51243
+ }],
50678
51244
  "webrtcSession.addIceCandidate": [{
50679
51245
  name: "deviceId",
50680
51246
  form: "single",
@@ -51412,7 +51978,7 @@ var PreviewTextField = string().max(200);
51412
51978
  * Whether the notification's preview is a STILL or a short animation.
51413
51979
  *
51414
51980
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
51415
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
51981
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
51416
51982
  * night reads better as three seconds of motion than as one frame of it. Both
51417
51983
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
51418
51984
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -51550,6 +52116,7 @@ TimelapseRuleInputSchema.extend({
51550
52116
  createdAt: number(),
51551
52117
  updatedAt: number()
51552
52118
  });
52119
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
51553
52120
  object({
51554
52121
  /**
51555
52122
  * Fraction of the box's own size added on EACH side before cutting.