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