@camstack/addon-provider-dreame 0.2.119 → 0.2.120

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
@@ -52899,7 +52899,7 @@ var DreameCameraStream = class extends TypedEmitter {
52899
52899
  }
52900
52900
  };
52901
52901
  //#endregion
52902
- //#region ../types/dist/event-category-C5xZWqz6.mjs
52902
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
52903
52903
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
52904
52904
  EventCategory["SystemBoot"] = "system.boot";
52905
52905
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -53432,6 +53432,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
53432
53432
  */
53433
53433
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
53434
53434
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
53435
+ /**
53436
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
53437
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
53438
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
53439
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
53440
+ * for a camera with no attached sensor). Providers must not emit
53441
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
53442
+ * keeps it so (camera-grid is a named, deferred exception).
53443
+ */
53435
53444
  EventCategory["ProviderMotion"] = "provider.motion";
53436
53445
  EventCategory["ProviderDetection"] = "provider.detection";
53437
53446
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -58270,7 +58279,7 @@ var ZodIssueCode = {
58270
58279
  var ZodFirstPartyTypeKind;
58271
58280
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
58272
58281
  //#endregion
58273
- //#region ../types/dist/sleep-gU6hqv4_.mjs
58282
+ //#region ../types/dist/sleep-CDCONfkt.mjs
58274
58283
  /**
58275
58284
  * The audio chunk plane's byte format, and the ONE expansion from a coded
58276
58285
  * window to float samples (D455).
@@ -60313,7 +60322,7 @@ function errMsg(err) {
60313
60322
  return String(err);
60314
60323
  }
60315
60324
  //#endregion
60316
- //#region ../types/dist/composition-Dq42XWp0.mjs
60325
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
60317
60326
  /**
60318
60327
  * The ffmpeg build every CamStack node downloads, per platform and arch.
60319
60328
  *
@@ -60367,21 +60376,20 @@ function portable(target) {
60367
60376
  }
60368
60377
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
60369
60378
  /**
60370
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
60371
- * valutatore puro del suo FRONTE.
60379
+ * THE table "which boolean of this device type counts as HIGH", and the
60380
+ * pure evaluator of its EDGE.
60372
60381
  *
60373
- * Viveva dentro il builtin virtual-doorbell
60374
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
60375
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
60376
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
60377
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
60378
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
60379
- * SPOSTA qui e il doorbell la ri-esporta.
60382
+ * ONE table for everyone who asks "is this device HIGH?": the
60383
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
60384
+ * sensor markers, the orchestrator's camera-sensors bridge and
60385
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
60386
+ * A second copy would diverge at the first cap added, and the symptom — "the
60387
+ * sensor rings the doorbell but does not record" — is exactly D62.
60380
60388
  *
60381
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
60382
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
60383
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
60384
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
60389
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
60390
+ * two must not be unified: that one answers "what is the state WORD for a
60391
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
60392
+ * boolean's EDGE counts". Deliberately different vocabularies.
60385
60393
  */
60386
60394
  /**
60387
60395
  * Known binary / switch source caps → the boolean slice field whose
@@ -61990,22 +61998,22 @@ var CLASS_MAP_MACRO_TARGETS = [
61990
61998
  "package"
61991
61999
  ];
61992
62000
  /**
61993
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
61994
- * un operatore può selezionare.
62001
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
62002
+ * an operator can select.
61995
62003
  *
61996
- * Sono le tre offerte dallo step `object-detection`
62004
+ * They are the three offered by the `object-detection` step
61997
62005
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
61998
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
61999
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
62000
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
62001
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
62006
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
62007
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
62008
+ * `package-detection`, whose enablement is driven by zones, and offering the
62009
+ * same word twice has already made an operator turn on the COCO proxy
62002
62010
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
62003
62011
  *
62004
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
62005
- * dello step e una seconda volta come union `FirstLevelMacro`
62006
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
62007
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
62008
- * successiva.
62012
+ * ONE list. Before today the same three were hand-written in the step's offer
62013
+ * and a second time as the union `FirstLevelMacro`
62014
+ * (`types/detection.ts`); a third copy for the recording trigger
62015
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
62016
+ * invisible.
62009
62017
  */
62010
62018
  var FIRST_LEVEL_MACRO_CLASSES = [
62011
62019
  "person",
@@ -62070,17 +62078,17 @@ var RecordingStorageModeSchema = _enum([
62070
62078
  "on-device-decision"
62071
62079
  ]);
62072
62080
  /**
62073
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
62074
- * tre offerte dallo step `object-detection`, da UNA lista
62081
+ * The macro classes that can open a recording window — the same
62082
+ * three offered by the `object-detection` step, from ONE list
62075
62083
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
62076
62084
  */
62077
62085
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
62078
62086
  /**
62079
- * True quando `values` non ripete un elemento.
62087
+ * True when `values` does not repeat an element.
62080
62088
  *
62081
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
62082
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
62083
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
62089
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
62090
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
62091
+ * would count its windows twice in `segmentMissedByMs`.
62084
62092
  */
62085
62093
  var noDuplicates = (values) => new Set(values).size === values.length;
62086
62094
  /** Which detectors trigger an `events`-mode band. */
@@ -62088,34 +62096,34 @@ var RecordingTriggersSchema = object({
62088
62096
  motion: boolean().optional(),
62089
62097
  audioThresholdDbfs: number().optional(),
62090
62098
  /**
62091
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
62092
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
62093
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
62094
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
62099
+ * The macro classes whose detection opens a window. ABSENT = the source
62100
+ * is not listened to; an EMPTY array is rejected, because "events band, object
62101
+ * trigger on, no class" is the same shape "enabled and records
62102
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
62095
62103
  *
62096
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
62097
- * quelle che hanno attraversato `enabledMacroClasses`, i
62098
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
62099
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
62100
- * finestre — vedi `recorder/object-trigger.ts`.
62104
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
62105
+ * those that went through `enabledMacroClasses`, the
62106
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
62107
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
62108
+ * windows — see `recorder/object-trigger.ts`.
62101
62109
  */
62102
62110
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
62103
62111
  /**
62104
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
62105
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
62112
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
62113
+ * is not listened to; an empty array is rejected for the same reason as
62106
62114
  * `objectClasses`.
62107
62115
  *
62108
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
62109
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
62110
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
62111
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
62112
- * device (D12) — mai un elenco globale di cap.
62116
+ * These are SOURCE device ids, not cameras: the band names them, so the
62117
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
62118
+ * does no RPC. The OFFER from which the operator picks them is another question, and
62119
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
62120
+ * device (D12) — never a global list of caps.
62113
62121
  *
62114
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
62115
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
62116
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
62117
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
62118
- * registrare.
62122
+ * What "high" means depends on the device TYPE and is not decided here:
62123
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
62124
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
62125
+ * the level: a contact found already open at runner restart does not
62126
+ * record.
62119
62127
  */
62120
62128
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
62121
62129
  });
@@ -63192,7 +63200,7 @@ var DecoderSessionConfigSchema = object({
63192
63200
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
63193
63201
  * thing: the logging settings document on the `system` cap. Two authorities
63194
63202
  * over the values is the exact defect
63195
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
63203
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
63196
63204
  * remove; re-introducing it from the cure side would be grotesque.
63197
63205
  *
63198
63206
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -64903,7 +64911,7 @@ var BrokerStatusEnum = _enum([
64903
64911
  "unreachable",
64904
64912
  "error"
64905
64913
  ]);
64906
- var BrokerInfoSchema$1 = object({
64914
+ var BrokerInfoSchema = object({
64907
64915
  /** Stable broker id. Persisted; survives addon restarts. */
64908
64916
  id: string(),
64909
64917
  /** Addon id of the provider that OWNS this broker.
@@ -65036,7 +65044,7 @@ var GetStateInputSchema = object({
65036
65044
  * HA: entity_id (returns the cached entity state). */
65037
65045
  key: string()
65038
65046
  });
65039
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
65047
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
65040
65048
  kind: "mutation",
65041
65049
  auth: "admin"
65042
65050
  }), method(RemoveInputSchema, _void(), {
@@ -66747,7 +66755,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
66747
66755
  *
66748
66756
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
66749
66757
  * was wrong — corrected 2026-08-26 after the hop map
66750
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
66758
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
66751
66759
  * There is **no Zod parse at all** between the door and the engine: the
66752
66760
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
66753
66761
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -67627,7 +67635,17 @@ var SiteZoneSchema = object({
67627
67635
  var ProviderStatusSchema = object({
67628
67636
  connected: boolean(),
67629
67637
  deviceCount: number(),
67630
- error: string().optional()
67638
+ error: string().optional(),
67639
+ /**
67640
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
67641
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
67642
+ * which every provider bundles, so only a provider BUILT from D696-amended
67643
+ * code says it. ABSENT means an older provider that may still write it (raw
67644
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
67645
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
67646
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
67647
+ */
67648
+ motionSliceWriter: literal("orchestrator").optional()
67631
67649
  });
67632
67650
  object({
67633
67651
  externalId: string(),
@@ -68506,109 +68524,10 @@ method(object({
68506
68524
  deviceIds: array(number()).readonly(),
68507
68525
  caps: array(string()).readonly().optional()
68508
68526
  }), record(string(), record(string(), unknown().nullable())));
68509
- /**
68510
- * Doorbell button cap. Two kinds of providers coexist behind this cap
68511
- * name (same pattern as `snapshot`):
68512
- *
68513
- * - **Native** providers: registered per-device by device-driver
68514
- * addons via `ctx.registerNativeCap` — either on a
68515
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
68516
- * or directly on the camera (Reolink registers at camera level).
68517
- * Emits an `onPressed` event every time the firmware pushes a
68518
- * ring; status tracks the last press and a pressCount since start
68519
- * (diagnostic).
68520
- *
68521
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
68522
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
68523
- * device (contact / switch / event-emitter …) into a doorbell for
68524
- * a camera. `defaultActive: false` — the operator explicitly binds
68525
- * it per camera in the device-bindings UI, then picks the source
68526
- * device + trigger in the per-device settings.
68527
- *
68528
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
68529
- * — subscribers listening at the camera level receive ring events
68530
- * with `via[]` populated. No code on the parent needed.
68531
- */
68532
- var DoorbellStatusSchema = object({
68533
- /** Ms epoch of the last press. null = never observed since this provider started. */
68534
- lastPressedAt: number().nullable(),
68535
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
68536
- pressCountSinceStart: number()
68537
- });
68538
- var DoorbellPressEventSchema = object({
68539
- deviceId: number(),
68540
- timestamp: number()
68541
- });
68542
- /**
68543
- * The `doorbell-source` extension slot's editable value (D648): the camera's
68544
- * virtual-doorbell trigger devices, exactly what the wrapper's
68545
- * `doorbellSources` persists (as `{ deviceId }` records).
68546
- */
68547
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
68548
- /**
68549
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
68550
- * doorbell, owned by the `virtual-doorbell` wrapper over its
68551
- * `doorbellSources` store (D648). A source rings when one of its
68552
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
68553
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
68554
- * reports it, it never writes it.
68555
- */
68556
- var DOORBELL_SOURCE_SLOT = {
68557
- id: "doorbell-source",
68558
- label: "Doorbell trigger devices",
68559
- 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.",
68560
- shape: "association",
68561
- hostDeviceTypes: [DeviceType.Camera],
68562
- sourceCaps: SOURCE_CAPS,
68563
- cardinality: "many",
68564
- value: DoorbellSourceSlotValueSchema
68565
- };
68566
- var doorbellCapability = {
68567
- name: "doorbell",
68568
- scope: "device",
68569
- deviceNative: true,
68570
- mode: "singleton",
68571
- kind: "wrapper",
68572
- defaultActive: false,
68573
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
68574
- extensionSlots: [DOORBELL_SOURCE_SLOT],
68575
- methods: {},
68576
- events: {
68577
- /**
68578
- * Fires once per physical press. Reolink delivers via Baichuan
68579
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
68580
- * release/duration — it's a pulse.
68581
- */
68582
- onPressed: {
68583
- data: DoorbellPressEventSchema,
68584
- fromState: {
68585
- field: "lastPressedAt",
68586
- on: "advance"
68587
- }
68588
- } },
68589
- status: {
68590
- schema: DoorbellStatusSchema,
68591
- kind: "push"
68592
- },
68593
- /**
68594
- * Runtime-state slice — last press timestamp + lifetime press count.
68595
- * Mirrored by the kernel and readable via
68596
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
68597
- * without subscribing.
68598
- */
68599
- runtimeState: DoorbellStatusSchema,
68600
- /**
68601
- * 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.
68602
- *
68603
- * See `RuntimeStateDurability`. Enforced by
68604
- * `scripts/check-runtime-state-durability.ts`.
68605
- */
68606
- durability: "restored"
68607
- };
68608
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
68609
- DeviceType.Camera, DeviceType.Camera;
68527
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
68528
+ DeviceType.Camera;
68610
68529
  /** A slot's editable value, discriminated on `slot`. */
68611
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
68530
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
68612
68531
  DeviceType.Camera;
68613
68532
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
68614
68533
  state: literal("unreachable"),
@@ -68645,10 +68564,11 @@ var ExtensionSlotSourceSchema = object({
68645
68564
  });
68646
68565
  /**
68647
68566
  * A DIFFERENT authority that gates whether the slot's sources do anything —
68648
- * reported read-only, named, never written through this contract (D62). The
68649
- * virtual doorbell's sources ring only while the wrapper is bound to the
68650
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
68651
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
68567
+ * reported read-only, named, never written through this contract (D62) — e.g.
68568
+ * a slot whose sources act only while a wrapper is bound to the host, a
68569
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
68570
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
68571
+ * not be read; it is not "inactive" (D315).
68652
68572
  */
68653
68573
  var ExtensionSlotActivationSchema = object({
68654
68574
  state: _enum([
@@ -68664,7 +68584,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
68664
68584
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
68665
68585
  slotRef: string(),
68666
68586
  slot: ExtensionSlotIdSchema,
68667
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
68587
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
68668
68588
  authority: string(),
68669
68589
  activation: ExtensionSlotActivationSchema.nullable(),
68670
68590
  value: ExtensionSlotValueSchema,
@@ -68942,7 +68862,7 @@ method(object({
68942
68862
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
68943
68863
  * ends in a log line, and a log line is the thing the operator asked to stop
68944
68864
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
68945
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
68865
+ * 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
68946
68866
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
68947
68867
  * media blackout were both diagnosed. The counters stay; this is where they can
68948
68868
  * be READ.
@@ -70318,7 +70238,7 @@ var BrokerStatusSchema$1 = _enum([
70318
70238
  "unreachable",
70319
70239
  "tls-error"
70320
70240
  ]);
70321
- var BrokerInfoSchema = object({
70241
+ var BrokerInfoSchema$1 = object({
70322
70242
  id: string(),
70323
70243
  name: string(),
70324
70244
  url: string(),
@@ -70381,7 +70301,7 @@ var StatusSchema = object({
70381
70301
  brokerCount: number(),
70382
70302
  embeddedRunning: boolean()
70383
70303
  });
70384
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
70304
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
70385
70305
  kind: "mutation",
70386
70306
  auth: "admin"
70387
70307
  }), method(IdInputSchema, _void(), {
@@ -72595,78 +72515,16 @@ var NcRuleInputSchema = object({
72595
72515
  */
72596
72516
  confirm: NcConfirmSchema.optional(),
72597
72517
  /**
72598
- * WAIT for face/plate recognition before saying anything.
72599
- *
72600
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
72601
- * send; the identity is neither. A face is confirmed after `confirmFrames`
72602
- * agreeing observations — p50 **11.4 s** after the track was first seen,
72603
- * measured on this hub — and an `immediate` rule enqueues on the first object
72604
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
72605
- * immediate path, and no amount of media re-resolution fixes a sentence.
72606
- *
72607
- * Only two honest answers exist, and this flag picks between them. It has
72608
- * effect ONLY on a rule that declares a recognition scope
72609
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
72610
- * other rule there is nothing to wait for and the flag is inert.
72611
- *
72612
- * | value | what happens |
72613
- * | --- | --- |
72614
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
72615
- * | 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) |
72616
- *
72617
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
72618
- * on the addon cap path, and absent has to keep meaning exactly what every
72619
- * rule authored before this field meant.
72620
- *
72621
- * The cost of `true` is stated here because the editor states it too: a rule
72622
- * that waits also inherits track-close SEMANTICS — its `zones` condition
72623
- * tests every zone the track visited and a `crossing` condition can no longer
72624
- * be satisfied, because a closed track carries no crossing.
72518
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
72519
+ * seconds; the rule sends ONE message when the window closes — early, once every
72520
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
72521
+ * the rule matched, with one mosaic tile per subject.
72522
+ * Absent = plain immediate (one message per track, at the first match).
72523
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
72524
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
72525
+ * path does not run Zod defaults.
72625
72526
  */
72626
- waitForEnhancement: boolean().optional(),
72627
- /**
72628
- * GROUP a burst of subjects into ONE notification that grows.
72629
- *
72630
- * Seconds of quiet after the last matching subject before the burst is
72631
- * considered over. While it is open, the first subject enqueues immediately —
72632
- * **exactly as today, with no added latency** — and every real growth (a new
72633
- * subject, or a name confirmed on one already in it) REPLACES that
72634
- * notification with an updated one naming everybody. The push carries the
72635
- * group's own coalescing tag, so the phone replaces rather than stacks.
72636
- *
72637
- * `0` / absent = off, and off is today's behaviour byte for byte.
72638
- *
72639
- * ### Why an idle cutoff and not a window
72640
- *
72641
- * The measured seven-person arrival on device 590 spans 110 s with every
72642
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
72643
- * idle cutoff holds it as one and ends it when the arrival actually ends.
72644
- * 30 s is a widely shipped value for the same decision.
72645
- *
72646
- * ### What it replaces
72647
- *
72648
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
72649
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
72650
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
72651
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
72652
- * A group collapses the same volume by MERGING, so the cooldown becomes a
72653
- * budget over GROUPS — which is what it always meant — and a growth is never
72654
- * throttled by the window its own first member spent.
72655
- *
72656
- * ### Interaction with {@link waitForEnhancement}
72657
- *
72658
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
72659
- * TRACK CLOSE, so with both set the group is opened by the first member to
72660
- * CLOSE — already carrying its name — and grows as later members close. That
72661
- * is later, and complete. With grouping alone the group opens on the first
72662
- * object event and picks up names as they are confirmed, through the growth
72663
- * path. Neither combination fires twice for one subject.
72664
- *
72665
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
72666
- * on the addon cap path, so absent must keep meaning what it meant before this
72667
- * field existed.
72668
- */
72669
- groupIdleSec: number().int().min(0).max(600).optional()
72527
+ groupingSec: number().int().min(5).max(60).optional()
72670
72528
  });
72671
72529
  /**
72672
72530
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -72714,9 +72572,10 @@ var NcRuleClearableKeySchema = _enum([
72714
72572
  "targetUsers",
72715
72573
  "snoozeOptions",
72716
72574
  "snoozeAllowGlobal",
72717
- "waitForEnhancement",
72718
72575
  "actions",
72719
72576
  "confirm",
72577
+ "groupingSec",
72578
+ "waitForEnhancement",
72720
72579
  "groupIdleSec"
72721
72580
  ]);
72722
72581
  var NcRuleUpdateInputSchema = object({
@@ -72738,9 +72597,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
72738
72597
  */
72739
72598
  disabledTargetIds: array(string()).default([])
72740
72599
  });
72600
+ /**
72601
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
72602
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
72603
+ * job is not an open state, and the alarm stays instant.
72604
+ */
72605
+ var NcStateSummarySectionIdSchema = _enum([
72606
+ "device-state",
72607
+ "streams",
72608
+ "battery",
72609
+ "consumables",
72610
+ "tanks",
72611
+ "detection-blind",
72612
+ "nodes",
72613
+ "addons",
72614
+ "updates"
72615
+ ]);
72741
72616
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
72742
72617
  var NcStateSummaryPreviewSectionSchema = object({
72743
- id: string(),
72618
+ id: NcStateSummarySectionIdSchema,
72744
72619
  status: _enum(["read", "unavailable"]),
72745
72620
  items: number().int().nonnegative(),
72746
72621
  reason: string().optional()
@@ -72750,7 +72625,7 @@ var NcStateSummaryPreviewSectionSchema = object({
72750
72625
  * a `rule` split (no `section`), one section's on a `section` split.
72751
72626
  */
72752
72627
  var NcStateSummaryPreviewRowSchema = object({
72753
- section: string().optional(),
72628
+ section: NcStateSummarySectionIdSchema.optional(),
72754
72629
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
72755
72630
  title: string(),
72756
72631
  text: string(),
@@ -73187,6 +73062,29 @@ object({
73187
73062
  firstAt: number(),
73188
73063
  lastAt: number()
73189
73064
  });
73065
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
73066
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
73067
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
73068
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
73069
+ var NcAlarmModeDelaysListSchema = array(object({
73070
+ mode: AlarmArmModeSchema,
73071
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
73072
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
73073
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
73074
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
73075
+ var NcAlarmModeDelaysEditListSchema = array(object({
73076
+ mode: AlarmArmModeSchema,
73077
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
73078
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
73079
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
73080
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
73081
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
73082
+ var NcAlarmNonBlockingEditSchema = object({
73083
+ mode: AlarmArmModeSchema,
73084
+ deviceId: number().int().positive(),
73085
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
73086
+ nonBlocking: boolean()
73087
+ });
73190
73088
  /**
73191
73089
  * The per-mode lists, at most one per mode. Two lists for one mode have no
73192
73090
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -73195,10 +73093,10 @@ object({
73195
73093
  var NcAlarmNonBlockingListSchema = array(object({
73196
73094
  mode: AlarmArmModeSchema,
73197
73095
  deviceIds: array(number().int()).max(200)
73198
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
73096
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
73199
73097
  /**
73200
- * The three durations the panel's state machine runs on, who hears about its
73201
- * transitions, and which openings each mode tolerates.
73098
+ * The three durations — global, and per mode since D697 — the panel's state
73099
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
73202
73100
  *
73203
73101
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
73204
73102
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -73208,15 +73106,15 @@ var NcAlarmNonBlockingListSchema = array(object({
73208
73106
  */
73209
73107
  var NcAlarmSettingsSchema = object({
73210
73108
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
73211
- exitDelaySec: number().int().min(0).max(600),
73109
+ exitDelaySec: NcAlarmDelaySecSchema,
73212
73110
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
73213
- entryDelaySec: number().int().min(0).max(600),
73111
+ entryDelaySec: NcAlarmDelaySecSchema,
73214
73112
  /**
73215
73113
  * How long `triggered` lasts before the panel re-arms itself.
73216
73114
  * **0 = until an operator disarms it** — the behaviour before this field
73217
73115
  * existed, and therefore what an untouched install keeps doing.
73218
73116
  */
73219
- triggeredDurationSec: number().int().min(0).max(3600),
73117
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
73220
73118
  /**
73221
73119
  * Deprecated by D630 — every transition is announced. Parsed, never read;
73222
73120
  * remove after one release. Optional so an older admin's patch (which still
@@ -73239,17 +73137,30 @@ var NcAlarmSettingsSchema = object({
73239
73137
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
73240
73138
  * parses as "every opening blocks" — the behaviour it was written under.
73241
73139
  */
73242
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
73140
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
73141
+ /**
73142
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
73143
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
73144
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
73145
+ */
73146
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
73243
73147
  });
73244
73148
  /**
73245
73149
  * Every field optional — a tab edits one control at a time.
73246
73150
  *
73247
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
73248
- * remove an inner `.default()`, so a patch that never named the field would
73249
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
73250
- * (the same trap {@link NcRulePatchSchema} documents).
73151
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
73152
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
73153
+ * named the field would parse to `[]` and wipe every mode's list on an
73154
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
73155
+ * `modeDelays` means EDITS, not the stored overrides.
73251
73156
  */
73252
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
73157
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
73158
+ nonBlocking: NcAlarmNonBlockingListSchema,
73159
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
73160
+ modeDelays: NcAlarmModeDelaysEditListSchema,
73161
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
73162
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
73163
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
73253
73164
  /**
73254
73165
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
73255
73166
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -73349,6 +73260,28 @@ var NcAlarmConfigSchema = object({
73349
73260
  */
73350
73261
  live: NcAlarmLiveSchema.optional()
73351
73262
  });
73263
+ var NcAlarmSensorReadingSchema = _enum([
73264
+ "open",
73265
+ "closed",
73266
+ "unknown",
73267
+ "not-opening"
73268
+ ]);
73269
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
73270
+ var NcAlarmSensorStateSchema = object({
73271
+ deviceId: number().int().positive(),
73272
+ reading: NcAlarmSensorReadingSchema,
73273
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
73274
+ state: string().nullable(),
73275
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
73276
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
73277
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
73278
+ online: boolean().nullable()
73279
+ });
73280
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
73281
+ var NcAlarmSensorsSchema = object({
73282
+ sensors: array(NcAlarmSensorStateSchema),
73283
+ readAt: number().int().nonnegative()
73284
+ });
73352
73285
  /**
73353
73286
  * ONE rule's demand on ONE camera's clip ring.
73354
73287
  *
@@ -73439,7 +73372,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
73439
73372
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
73440
73373
  kind: "mutation",
73441
73374
  auth: "admin"
73442
- });
73375
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
73443
73376
  /**
73444
73377
  * Zod schemas for persisted record types.
73445
73378
  *
@@ -73786,12 +73719,26 @@ var CameraSensorRefSchema = object({
73786
73719
  function cameraSensorRefKey(ref) {
73787
73720
  return `${ref.addonId}/${ref.stableId}`;
73788
73721
  }
73789
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
73790
- var CameraSensorsModeSchema = _enum(["in-addition"]);
73791
- var CameraSensorsConfigSchema = object({
73792
- mode: CameraSensorsModeSchema,
73793
- sensors: array(CameraSensorRefSchema).min(1).max(8)
73794
- }).superRefine((value, ctx) => {
73722
+ /**
73723
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
73724
+ * `replace`: its motion is the camera's, and while one is READY the camera's
73725
+ * own motion no longer counts on its own. `confirm`: while one is READY the
73726
+ * camera's own motion counts only while a confirm sensor is active — with or
73727
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
73728
+ */
73729
+ var CameraSensorModeSchema = _enum([
73730
+ "in-addition",
73731
+ "confirm",
73732
+ "replace"
73733
+ ]);
73734
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
73735
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
73736
+ /**
73737
+ * A camera's attached sensors. A CS-1 row carried an envelope
73738
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
73739
+ * what the write stores (D672 rule 3), so it is never written again.
73740
+ */
73741
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
73795
73742
  const seen = /* @__PURE__ */ new Set();
73796
73743
  value.sensors.forEach((ref, index) => {
73797
73744
  const key = cameraSensorRefKey(ref);
@@ -73803,39 +73750,41 @@ var CameraSensorsConfigSchema = object({
73803
73750
  seen.add(key);
73804
73751
  });
73805
73752
  });
73806
- var RefFields = {
73753
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
73754
+ var AttachmentFields = {
73807
73755
  addonId: string(),
73808
- stableId: string()
73756
+ stableId: string(),
73757
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
73809
73758
  };
73810
73759
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
73811
73760
  object({
73812
- ...RefFields,
73761
+ ...AttachmentFields,
73813
73762
  state: literal("ready"),
73814
73763
  deviceId: number(),
73815
73764
  name: string(),
73816
73765
  caps: array(string()).readonly()
73817
73766
  }),
73818
73767
  object({
73819
- ...RefFields,
73768
+ ...AttachmentFields,
73820
73769
  state: literal("offline"),
73821
73770
  deviceId: number(),
73822
73771
  name: string(),
73823
73772
  reason: _enum(["offline", "disabled"])
73824
73773
  }),
73825
73774
  object({
73826
- ...RefFields,
73775
+ ...AttachmentFields,
73827
73776
  state: literal("missing"),
73828
73777
  reason: string()
73829
73778
  }),
73830
73779
  object({
73831
- ...RefFields,
73780
+ ...AttachmentFields,
73832
73781
  state: literal("unsupported"),
73833
73782
  deviceId: number(),
73834
73783
  name: string(),
73835
73784
  reason: string()
73836
73785
  }),
73837
73786
  object({
73838
- ...RefFields,
73787
+ ...AttachmentFields,
73839
73788
  state: literal("unreadable"),
73840
73789
  reason: string()
73841
73790
  })
@@ -73848,17 +73797,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
73848
73797
  * say.
73849
73798
  */
73850
73799
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
73800
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
73801
+ var CameraOwnMotionSchema = _enum([
73802
+ "always",
73803
+ "when-confirmed",
73804
+ "never"
73805
+ ]);
73806
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
73807
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
73808
+ /**
73809
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
73810
+ * never the effective value. The camera's `motion` slice is the effective one,
73811
+ * so a view of the camera's own row reads this.
73812
+ * - `atMs`: when the bridge received the camera's last own edge.
73813
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
73814
+ * AND it is younger than the window the bridge counts the camera's own motion
73815
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
73816
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
73817
+ * within the window; a status read is a snapshot, so a live view re-asks.
73818
+ * Absent = this orchestrator has not received the camera's own motion since it
73819
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
73820
+ */
73821
+ var CameraRawLevelSchema = object({
73822
+ detected: boolean(),
73823
+ atMs: number()
73824
+ });
73851
73825
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
73852
- object({ state: literal("not-configured") }),
73826
+ object({
73827
+ state: literal("not-configured"),
73828
+ cameraLevel: CameraRawLevelSchema.optional()
73829
+ }),
73853
73830
  object({
73854
73831
  state: literal("unreadable"),
73855
- reason: string()
73832
+ reason: string(),
73833
+ cameraLevel: CameraRawLevelSchema.optional()
73856
73834
  }),
73857
73835
  object({
73858
73836
  state: literal("configured"),
73859
- mode: CameraSensorsModeSchema,
73837
+ cameraLevel: CameraRawLevelSchema.optional(),
73860
73838
  sensors: array(CameraSensorAttachmentSchema).readonly(),
73861
- notForwarded: CameraSensorsNotForwardedSchema.optional()
73839
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
73840
+ cameraMotion: CameraOwnMotionSchema.optional(),
73841
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
73842
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
73862
73843
  })
73863
73844
  ]);
73864
73845
  Object.freeze({
@@ -74543,14 +74524,14 @@ var TrackSchema = object({
74543
74524
  * `derive-returned-null tile=standin`,
74544
74525
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
74545
74526
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
74546
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
74527
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
74547
74528
  * tile is a face/plate stand-in, a raster crop, or an icon.
74548
74529
  *
74549
74530
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
74550
74531
  * the TILE ranked below native, so a track whose thumbnail landed natively
74551
74532
  * while its key frame missed carried no reason at all — three of the four
74552
74533
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
74553
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
74534
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
74554
74535
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
74555
74536
  * lastFrame copy source`), so its absence is now on this line whatever the
74556
74537
  * tile ended up being.
@@ -74637,7 +74618,7 @@ var MotionEventSchema = object({
74637
74618
  /**
74638
74619
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
74639
74620
  * first entry is always `0`) of every genuine off→on transition the
74640
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
74621
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
74641
74622
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
74642
74623
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
74643
74624
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -75161,6 +75142,7 @@ var KeyEventSchema = object({
75161
75142
  bestEventId: string(),
75162
75143
  /** Track lifetime in ms (lastSeen - firstSeen). */
75163
75144
  windowMs: number().optional(),
75145
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
75164
75146
  ...TrackFlagFields,
75165
75147
  ...TrackRetrainFields
75166
75148
  });
@@ -77089,8 +77071,10 @@ var RunnerCameraConfigSchema = object({
77089
77071
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
77090
77072
  * analyzer providers) running on decoded frames in this runner.
77091
77073
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
77092
- * analytics). The provider emits ProviderMotion
77093
- * events; the orchestrator forwards to `reportMotion`.
77074
+ * analytics). The provider emits its raw push as `ProviderMotion`
77075
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
77076
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
77077
+ * `reportMotion`.
77094
77078
  */
77095
77079
  motionSources: MotionSourcesSchema.default(["analyzer"]),
77096
77080
  /**
@@ -77267,7 +77251,15 @@ var RunnerLocalLoadSchema = object({
77267
77251
  hasGpu: boolean(),
77268
77252
  inferenceBackend: string().optional(),
77269
77253
  cpuCores: number().optional()
77270
- })
77254
+ }),
77255
+ /**
77256
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
77257
+ * runner never writes it. ABSENT = a runner older than D696, which still
77258
+ * writes the slice from its phase machine; the orchestrator does not write
77259
+ * while any runner node is absent-or-unanswered, so one slice never has two
77260
+ * writers.
77261
+ */
77262
+ motionSliceWriter: literal("orchestrator").optional()
77271
77263
  });
77272
77264
  /**
77273
77265
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -79932,7 +79924,7 @@ var ClipPlaybackSchema = object({
79932
79924
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
79933
79925
  * time the camera is awake for its own reasons — is deliberately not a member:
79934
79926
  * it was proposed, it is free on the battery, and the operator declined it on
79935
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
79927
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
79936
79928
  * D558 "Considered and not taken").
79937
79929
  */
79938
79930
  var ClipWakeSchema = _enum(["authorised"]);
@@ -80193,7 +80185,7 @@ DeviceType.Camera, method(object({
80193
80185
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
80194
80186
  * assumed the answer was a fan-out over everything a camera has. The
80195
80187
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
80196
- * solo"* — so the list is asked of one provider at a time and there is
80188
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
80197
80189
  * nothing to filter out of it.
80198
80190
  */
80199
80191
  provider: string().min(1)
@@ -82813,6 +82805,70 @@ onStatusChanged: { data: object({
82813
82805
  * whether persisting is worth a SQLite commit. */
82814
82806
  volatileStateFields: ["lastChangedAt"]
82815
82807
  };
82808
+ var DoorbellStatusSchema = object({
82809
+ /** Ms epoch of the last press. null = never observed since this provider started. */
82810
+ lastPressedAt: number().nullable(),
82811
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
82812
+ pressCountSinceStart: number()
82813
+ });
82814
+ var DoorbellPressEventSchema = object({
82815
+ deviceId: number(),
82816
+ timestamp: number()
82817
+ });
82818
+ /**
82819
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
82820
+ * they are the same cap:
82821
+ *
82822
+ * - **Native** providers, registered per device by a driver addon through
82823
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
82824
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
82825
+ * camera level). They emit `onPressed` on every firmware ring.
82826
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
82827
+ * the cap, its `lastPressedAt` rising from the sources the operator
82828
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
82829
+ * from that field's advance (`fromState`).
82830
+ *
82831
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
82832
+ */
82833
+ var doorbellCapability = {
82834
+ name: "doorbell",
82835
+ scope: "device",
82836
+ deviceNative: true,
82837
+ mode: "singleton",
82838
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
82839
+ methods: {},
82840
+ events: {
82841
+ /**
82842
+ * Fires once per physical press. Reolink delivers via Baichuan
82843
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
82844
+ * release/duration — it's a pulse.
82845
+ */
82846
+ onPressed: {
82847
+ data: DoorbellPressEventSchema,
82848
+ fromState: {
82849
+ field: "lastPressedAt",
82850
+ on: "advance"
82851
+ }
82852
+ } },
82853
+ status: {
82854
+ schema: DoorbellStatusSchema,
82855
+ kind: "push"
82856
+ },
82857
+ /**
82858
+ * Runtime-state slice — last press timestamp + lifetime press count.
82859
+ * Mirrored by the kernel and readable via
82860
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
82861
+ * without subscribing.
82862
+ */
82863
+ runtimeState: DoorbellStatusSchema,
82864
+ /**
82865
+ * 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.
82866
+ *
82867
+ * See `RuntimeStateDurability`. Enforced by
82868
+ * `scripts/check-runtime-state-durability.ts`.
82869
+ */
82870
+ durability: "restored"
82871
+ };
82816
82872
  /**
82817
82873
  * Enum-state sensor — a string value picked from a finite option set.
82818
82874
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -84957,9 +85013,9 @@ var MotionStatusSchema = object({
84957
85013
  /** Ms epoch of the last detected-true observation. Null if never detected. */
84958
85014
  lastDetectedAt: number().nullable(),
84959
85015
  /**
84960
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
84961
- * `null` while false and on every `Sensor` device (D475) — see that
84962
- * constant's doc for the one-authority rule.
85016
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
85017
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
85018
+ * device (D475) — see that constant's doc for the one-authority rule.
84963
85019
  *
84964
85020
  * ## Reading this field still arms nothing
84965
85021
  *
@@ -84977,34 +85033,31 @@ var MotionStatusSchema = object({
84977
85033
  * `addon-export-alexa/src/motion-clear-hold.ts` and
84978
85034
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
84979
85035
  *
84980
- * ## Who writes it
84981
- *
84982
- * - **Cameras** — the runner's phase machine, `active → watching` on
84983
- * `cooldown_expired`, which then writes this slice with
84984
- * `detected: false` (`handlePhaseChanged` in
84985
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
84986
- * matters most for the sources that only ever push a rising one:
84987
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
84988
- * a false.
84989
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
84990
- * provider pushes the false itself, from the upstream system's own
84991
- * state change. No phase machine is involved.
84992
- *
84993
- * ### The phase machine is CANONICAL, not sole — and that is a defect
84994
- *
84995
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
84996
- * phase machine is the sole writer for a camera. It is not.
84997
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
84998
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
84999
- * Hikvision's comment says why: it read THIS docblock, agreed the
85000
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
85001
- * two authorities can disagree about one slice, which this repo
85002
- * forbids, and the doc said otherwise — which is worse than saying
85003
- * nothing, because it reads as verification.
85004
- *
85005
- * This predates D475 and is not fixed there: the fix touches every
85006
- * camera provider. Recorded in D475's Consequences. Do not restore the
85007
- * "sole writer" wording without also removing the other writers.
85036
+ * ## Who writes it (D696)
85037
+ *
85038
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
85039
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
85040
+ * `camera-sensors/motion-slice.ts`), alongside the effective
85041
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
85042
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
85043
+ * device activity, as the camera's `motionSources` counts them. A source
85044
+ * that never sends a clear falls one window after its last `true`.
85045
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
85046
+ * writes this slice (not even a boot seed), and neither does the runner's
85047
+ * phase machine: its phase is "a session is attached" for every on-motion
85048
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
85049
+ * A provider's `isDetected` answers from the hub's slice.
85050
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
85051
+ * imports) — the provider pushes both edges itself, from the upstream
85052
+ * system's own state change. That is the sensor's own fact.
85053
+ *
85054
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
85055
+ * `motion` slice; each sensor writer is a named exemption.
85056
+ *
85057
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
85058
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
85059
+ * it, every provider seeded it at boot, and every session left it
85060
+ * `detected: true` after its detach.
85008
85061
  */
85009
85062
  autoClearAfterMs: number().nullable()
85010
85063
  });
@@ -85076,11 +85129,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
85076
85129
  */
85077
85130
  runtimeState: MotionStatusSchema,
85078
85131
  /**
85079
- * Runtime-state durability: **session** — every writer of this slice
85132
+ * Runtime-state durability: **session** — the writer of this slice
85080
85133
  * writes only on an EDGE, so a restored `detected: true` would stay
85081
85134
  * frozen until the next one instead of being corrected. The next edge
85082
- * re-publishes the real state. (On who the writers are, and why there
85083
- * is more than one, see `autoClearAfterMs` above.)
85135
+ * re-publishes the real state, and the orchestrator re-publishes every
85136
+ * camera when it starts writing (D696; on who writes it, see
85137
+ * `autoClearAfterMs` above).
85084
85138
  *
85085
85139
  * See `RuntimeStateDurability`. Enforced by
85086
85140
  * `scripts/check-runtime-state-durability.ts`.
@@ -87611,8 +87665,7 @@ var ptzAutotrackCapability = {
87611
87665
  deviceNative: true,
87612
87666
  mode: "singleton",
87613
87667
  /**
87614
- * Two kinds of provider behind one name, the same shape `snapshot` and
87615
- * `doorbell` use:
87668
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
87616
87669
  *
87617
87670
  * - **Native**: the camera's own firmware autotrack, registered per device by
87618
87671
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -87620,7 +87673,7 @@ var ptzAutotrackCapability = {
87620
87673
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
87621
87674
  * which follows a subject with `ptz.move` pulses driven by the detection
87622
87675
  * pipeline. `defaultActive: false` — the operator binds it per camera in
87623
- * the bindings UI, exactly as `virtual-doorbell` is bound.
87676
+ * the bindings UI.
87624
87677
  *
87625
87678
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
87626
87679
  * one switch for the function either way. A camera never has both driving its
@@ -88295,7 +88348,7 @@ var ReadGopBytesResultSchema = object({
88295
88348
  /**
88296
88349
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
88297
88350
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
88298
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
88351
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
88299
88352
  * a replay needs several seconds of native pixels, not one frame.
88300
88353
  *
88301
88354
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -91659,6 +91712,7 @@ var zoneRulesCapability = {
91659
91712
  */
91660
91713
  durability: "restored"
91661
91714
  };
91715
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
91662
91716
  /**
91663
91717
  * Accessory device helpers — shared across drivers.
91664
91718
  *
@@ -92718,13 +92772,14 @@ var BaseDeviceProvider = class extends BaseAddon {
92718
92772
  async getStatus() {
92719
92773
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
92720
92774
  const summary = this.restoreFailureSummary();
92721
- if (summary === null) return {
92775
+ const base = {
92722
92776
  connected: true,
92723
- deviceCount: all.length
92777
+ deviceCount: all.length,
92778
+ motionSliceWriter: "orchestrator"
92724
92779
  };
92780
+ if (summary === null) return base;
92725
92781
  return {
92726
- connected: true,
92727
- deviceCount: all.length,
92782
+ ...base,
92728
92783
  error: summary
92729
92784
  };
92730
92785
  }
@@ -98160,6 +98215,12 @@ Object.freeze({
98160
98215
  addonId: null,
98161
98216
  access: "view"
98162
98217
  },
98218
+ "notificationRules.getAlarmSensors": {
98219
+ capName: "notification-rules",
98220
+ capScope: "system",
98221
+ addonId: null,
98222
+ access: "view"
98223
+ },
98163
98224
  "notificationRules.getClipRetentionAsks": {
98164
98225
  capName: "notification-rules",
98165
98226
  capScope: "system",
@@ -101738,6 +101799,11 @@ Object.freeze({
101738
101799
  }
101739
101800
  });
101740
101801
  Object.freeze({
101802
+ "accessories.getStatus": [{
101803
+ name: "deviceId",
101804
+ form: "single",
101805
+ optional: false
101806
+ }],
101741
101807
  "accessories.setChildHidden": [{
101742
101808
  name: "childDeviceId",
101743
101809
  form: "single",
@@ -101757,6 +101823,11 @@ Object.freeze({
101757
101823
  form: "single",
101758
101824
  optional: false
101759
101825
  }],
101826
+ "airQualitySensor.getStatus": [{
101827
+ name: "deviceId",
101828
+ form: "single",
101829
+ optional: false
101830
+ }],
101760
101831
  "alarmPanel.arm": [{
101761
101832
  name: "deviceId",
101762
101833
  form: "single",
@@ -101767,11 +101838,36 @@ Object.freeze({
101767
101838
  form: "single",
101768
101839
  optional: false
101769
101840
  }],
101841
+ "alarmPanel.getStatus": [{
101842
+ name: "deviceId",
101843
+ form: "single",
101844
+ optional: false
101845
+ }],
101770
101846
  "alarmPanel.trigger": [{
101771
101847
  name: "deviceId",
101772
101848
  form: "single",
101773
101849
  optional: false
101774
101850
  }],
101851
+ "ambientLightSensor.getStatus": [{
101852
+ name: "deviceId",
101853
+ form: "single",
101854
+ optional: false
101855
+ }],
101856
+ "audioAnalysis.applyDeviceSettingsPatch": [{
101857
+ name: "deviceId",
101858
+ form: "single",
101859
+ optional: false
101860
+ }],
101861
+ "audioAnalysis.getDeviceLiveContribution": [{
101862
+ name: "deviceId",
101863
+ form: "single",
101864
+ optional: false
101865
+ }],
101866
+ "audioAnalysis.getDeviceSettingsContribution": [{
101867
+ name: "deviceId",
101868
+ form: "single",
101869
+ optional: false
101870
+ }],
101775
101871
  "audioAnalysis.resolveDeviceSettings": [{
101776
101872
  name: "deviceId",
101777
101873
  form: "single",
@@ -101812,16 +101908,36 @@ Object.freeze({
101812
101908
  form: "single",
101813
101909
  optional: false
101814
101910
  }],
101911
+ "automationControl.getStatus": [{
101912
+ name: "deviceId",
101913
+ form: "single",
101914
+ optional: false
101915
+ }],
101815
101916
  "automationControl.trigger": [{
101816
101917
  name: "deviceId",
101817
101918
  form: "single",
101818
101919
  optional: false
101819
101920
  }],
101921
+ "battery.getStatus": [{
101922
+ name: "deviceId",
101923
+ form: "single",
101924
+ optional: false
101925
+ }],
101820
101926
  "battery.wakeForStream": [{
101821
101927
  name: "deviceId",
101822
101928
  form: "single",
101823
101929
  optional: false
101824
101930
  }],
101931
+ "binary.getStatus": [{
101932
+ name: "deviceId",
101933
+ form: "single",
101934
+ optional: false
101935
+ }],
101936
+ "brightness.getStatus": [{
101937
+ name: "deviceId",
101938
+ form: "single",
101939
+ optional: false
101940
+ }],
101825
101941
  "brightness.setBrightness": [{
101826
101942
  name: "deviceId",
101827
101943
  form: "single",
@@ -101837,6 +101953,26 @@ Object.freeze({
101837
101953
  form: "single",
101838
101954
  optional: false
101839
101955
  }],
101956
+ "cameraCredentials.getStatus": [{
101957
+ name: "deviceId",
101958
+ form: "single",
101959
+ optional: false
101960
+ }],
101961
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
101962
+ name: "deviceId",
101963
+ form: "single",
101964
+ optional: false
101965
+ }],
101966
+ "cameraGridLayout.getDeviceLiveContribution": [{
101967
+ name: "deviceId",
101968
+ form: "single",
101969
+ optional: false
101970
+ }],
101971
+ "cameraGridLayout.getDeviceSettingsContribution": [{
101972
+ name: "deviceId",
101973
+ form: "single",
101974
+ optional: false
101975
+ }],
101840
101976
  "cameraGridLayout.getLayout": [{
101841
101977
  name: "deviceId",
101842
101978
  form: "single",
@@ -101852,6 +101988,21 @@ Object.freeze({
101852
101988
  form: "single",
101853
101989
  optional: false
101854
101990
  }],
101991
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
101992
+ name: "deviceId",
101993
+ form: "single",
101994
+ optional: false
101995
+ }],
101996
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
101997
+ name: "deviceId",
101998
+ form: "single",
101999
+ optional: false
102000
+ }],
102001
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
102002
+ name: "deviceId",
102003
+ form: "single",
102004
+ optional: false
102005
+ }],
101855
102006
  "cameraStreams.getBrokerStreams": [{
101856
102007
  name: "deviceId",
101857
102008
  form: "single",
@@ -101877,6 +102028,16 @@ Object.freeze({
101877
102028
  form: "single",
101878
102029
  optional: false
101879
102030
  }],
102031
+ "carbonMonoxide.getStatus": [{
102032
+ name: "deviceId",
102033
+ form: "single",
102034
+ optional: false
102035
+ }],
102036
+ "climateControl.getStatus": [{
102037
+ name: "deviceId",
102038
+ form: "single",
102039
+ optional: false
102040
+ }],
101880
102041
  "climateControl.setFanMode": [{
101881
102042
  name: "deviceId",
101882
102043
  form: "single",
@@ -101917,16 +102078,41 @@ Object.freeze({
101917
102078
  form: "single",
101918
102079
  optional: false
101919
102080
  }],
102081
+ "color.getStatus": [{
102082
+ name: "deviceId",
102083
+ form: "single",
102084
+ optional: false
102085
+ }],
101920
102086
  "color.setColor": [{
101921
102087
  name: "deviceId",
101922
102088
  form: "single",
101923
102089
  optional: false
101924
102090
  }],
102091
+ "connectivity.getStatus": [{
102092
+ name: "deviceId",
102093
+ form: "single",
102094
+ optional: false
102095
+ }],
102096
+ "consumables.getStatus": [{
102097
+ name: "deviceId",
102098
+ form: "single",
102099
+ optional: false
102100
+ }],
101925
102101
  "consumables.reset": [{
101926
102102
  name: "deviceId",
101927
102103
  form: "single",
101928
102104
  optional: false
101929
102105
  }],
102106
+ "contact.getStatus": [{
102107
+ name: "deviceId",
102108
+ form: "single",
102109
+ optional: false
102110
+ }],
102111
+ "control.getStatus": [{
102112
+ name: "deviceId",
102113
+ form: "single",
102114
+ optional: false
102115
+ }],
101930
102116
  "control.setValue": [{
101931
102117
  name: "deviceId",
101932
102118
  form: "single",
@@ -101937,6 +102123,11 @@ Object.freeze({
101937
102123
  form: "single",
101938
102124
  optional: false
101939
102125
  }],
102126
+ "cover.getStatus": [{
102127
+ name: "deviceId",
102128
+ form: "single",
102129
+ optional: false
102130
+ }],
101940
102131
  "cover.open": [{
101941
102132
  name: "deviceId",
101942
102133
  form: "single",
@@ -101962,6 +102153,11 @@ Object.freeze({
101962
102153
  form: "single",
101963
102154
  optional: false
101964
102155
  }],
102156
+ "dayNight.getStatus": [{
102157
+ name: "deviceId",
102158
+ form: "single",
102159
+ optional: false
102160
+ }],
101965
102161
  "dayNight.setSettings": [{
101966
102162
  name: "deviceId",
101967
102163
  form: "single",
@@ -101972,11 +102168,31 @@ Object.freeze({
101972
102168
  form: "single",
101973
102169
  optional: true
101974
102170
  }],
102171
+ "detectionPipeline.applyDeviceSettingsPatch": [{
102172
+ name: "deviceId",
102173
+ form: "single",
102174
+ optional: false
102175
+ }],
102176
+ "detectionPipeline.getDeviceLiveContribution": [{
102177
+ name: "deviceId",
102178
+ form: "single",
102179
+ optional: false
102180
+ }],
102181
+ "detectionPipeline.getDeviceSettingsContribution": [{
102182
+ name: "deviceId",
102183
+ form: "single",
102184
+ optional: false
102185
+ }],
101975
102186
  "deviceAdminLink.getAdminLink": [{
101976
102187
  name: "deviceId",
101977
102188
  form: "single",
101978
102189
  optional: false
101979
102190
  }],
102191
+ "deviceAdoption.getStatus": [{
102192
+ name: "deviceId",
102193
+ form: "single",
102194
+ optional: false
102195
+ }],
101980
102196
  "deviceAdoption.release": [{
101981
102197
  name: "camDeviceId",
101982
102198
  form: "single",
@@ -101992,6 +102208,11 @@ Object.freeze({
101992
102208
  form: "single",
101993
102209
  optional: false
101994
102210
  }],
102211
+ "deviceDiscovery.getStatus": [{
102212
+ name: "deviceId",
102213
+ form: "single",
102214
+ optional: false
102215
+ }],
101995
102216
  "deviceDiscovery.listDiscovered": [{
101996
102217
  name: "deviceId",
101997
102218
  form: "single",
@@ -102011,6 +102232,21 @@ Object.freeze({
102011
102232
  form: "single",
102012
102233
  optional: false
102013
102234
  }],
102235
+ "deviceExport.applyDeviceSettingsPatch": [{
102236
+ name: "deviceId",
102237
+ form: "single",
102238
+ optional: false
102239
+ }],
102240
+ "deviceExport.getDeviceLiveContribution": [{
102241
+ name: "deviceId",
102242
+ form: "single",
102243
+ optional: false
102244
+ }],
102245
+ "deviceExport.getDeviceSettingsContribution": [{
102246
+ name: "deviceId",
102247
+ form: "single",
102248
+ optional: false
102249
+ }],
102014
102250
  "deviceExtension.listCandidates": [{
102015
102251
  name: "deviceId",
102016
102252
  form: "single",
@@ -102359,6 +102595,26 @@ Object.freeze({
102359
102595
  form: "single",
102360
102596
  optional: false
102361
102597
  }],
102598
+ "deviceStatus.getStatus": [{
102599
+ name: "deviceId",
102600
+ form: "single",
102601
+ optional: false
102602
+ }],
102603
+ "doorbell.getStatus": [{
102604
+ name: "deviceId",
102605
+ form: "single",
102606
+ optional: false
102607
+ }],
102608
+ "enumSensor.getStatus": [{
102609
+ name: "deviceId",
102610
+ form: "single",
102611
+ optional: false
102612
+ }],
102613
+ "eventEmitter.getStatus": [{
102614
+ name: "deviceId",
102615
+ form: "single",
102616
+ optional: false
102617
+ }],
102362
102618
  "faceGallery.getFaceByTrack": [{
102363
102619
  name: "deviceId",
102364
102620
  form: "single",
@@ -102373,6 +102629,11 @@ Object.freeze({
102373
102629
  form: "array",
102374
102630
  optional: true
102375
102631
  }],
102632
+ "fanControl.getStatus": [{
102633
+ name: "deviceId",
102634
+ form: "single",
102635
+ optional: false
102636
+ }],
102376
102637
  "fanControl.setDirection": [{
102377
102638
  name: "deviceId",
102378
102639
  form: "single",
@@ -102393,6 +102654,26 @@ Object.freeze({
102393
102654
  form: "single",
102394
102655
  optional: false
102395
102656
  }],
102657
+ "featureProbe.getStatus": [{
102658
+ name: "deviceId",
102659
+ form: "single",
102660
+ optional: false
102661
+ }],
102662
+ "flood.getStatus": [{
102663
+ name: "deviceId",
102664
+ form: "single",
102665
+ optional: false
102666
+ }],
102667
+ "gas.getStatus": [{
102668
+ name: "deviceId",
102669
+ form: "single",
102670
+ optional: false
102671
+ }],
102672
+ "humidifier.getStatus": [{
102673
+ name: "deviceId",
102674
+ form: "single",
102675
+ optional: false
102676
+ }],
102396
102677
  "humidifier.setMode": [{
102397
102678
  name: "deviceId",
102398
102679
  form: "single",
@@ -102408,11 +102689,26 @@ Object.freeze({
102408
102689
  form: "single",
102409
102690
  optional: false
102410
102691
  }],
102692
+ "humiditySensor.getStatus": [{
102693
+ name: "deviceId",
102694
+ form: "single",
102695
+ optional: false
102696
+ }],
102697
+ "image.getStatus": [{
102698
+ name: "deviceId",
102699
+ form: "single",
102700
+ optional: false
102701
+ }],
102411
102702
  "imageSettings.getOptions": [{
102412
102703
  name: "deviceId",
102413
102704
  form: "single",
102414
102705
  optional: false
102415
102706
  }],
102707
+ "imageSettings.getStatus": [{
102708
+ name: "deviceId",
102709
+ form: "single",
102710
+ optional: false
102711
+ }],
102416
102712
  "imageSettings.setSettings": [{
102417
102713
  name: "deviceId",
102418
102714
  form: "single",
@@ -102423,6 +102719,11 @@ Object.freeze({
102423
102719
  form: "single",
102424
102720
  optional: false
102425
102721
  }],
102722
+ "intercom.getStatus": [{
102723
+ name: "deviceId",
102724
+ form: "single",
102725
+ optional: false
102726
+ }],
102426
102727
  "intercom.handleAnswer": [{
102427
102728
  name: "deviceId",
102428
102729
  form: "single",
@@ -102453,6 +102754,11 @@ Object.freeze({
102453
102754
  form: "single",
102454
102755
  optional: false
102455
102756
  }],
102757
+ "lawnMowerControl.getStatus": [{
102758
+ name: "deviceId",
102759
+ form: "single",
102760
+ optional: false
102761
+ }],
102456
102762
  "lawnMowerControl.pause": [{
102457
102763
  name: "deviceId",
102458
102764
  form: "single",
@@ -102463,6 +102769,11 @@ Object.freeze({
102463
102769
  form: "single",
102464
102770
  optional: false
102465
102771
  }],
102772
+ "lockControl.getStatus": [{
102773
+ name: "deviceId",
102774
+ form: "single",
102775
+ optional: false
102776
+ }],
102466
102777
  "lockControl.lock": [{
102467
102778
  name: "deviceId",
102468
102779
  form: "single",
@@ -102478,6 +102789,11 @@ Object.freeze({
102478
102789
  form: "single",
102479
102790
  optional: false
102480
102791
  }],
102792
+ "mediaPlayer.getStatus": [{
102793
+ name: "deviceId",
102794
+ form: "single",
102795
+ optional: false
102796
+ }],
102481
102797
  "mediaPlayer.next": [{
102482
102798
  name: "deviceId",
102483
102799
  form: "single",
@@ -102538,6 +102854,11 @@ Object.freeze({
102538
102854
  form: "single",
102539
102855
  optional: false
102540
102856
  }],
102857
+ "motion.getStatus": [{
102858
+ name: "deviceId",
102859
+ form: "single",
102860
+ optional: false
102861
+ }],
102541
102862
  "motion.isDetected": [{
102542
102863
  name: "deviceId",
102543
102864
  form: "single",
@@ -102548,11 +102869,31 @@ Object.freeze({
102548
102869
  form: "single",
102549
102870
  optional: false
102550
102871
  }],
102872
+ "motionDetection.applyDeviceSettingsPatch": [{
102873
+ name: "deviceId",
102874
+ form: "single",
102875
+ optional: false
102876
+ }],
102877
+ "motionDetection.getDeviceLiveContribution": [{
102878
+ name: "deviceId",
102879
+ form: "single",
102880
+ optional: false
102881
+ }],
102882
+ "motionDetection.getDeviceSettingsContribution": [{
102883
+ name: "deviceId",
102884
+ form: "single",
102885
+ optional: false
102886
+ }],
102551
102887
  "motionDetection.removeCamera": [{
102552
102888
  name: "deviceId",
102553
102889
  form: "single",
102554
102890
  optional: false
102555
102891
  }],
102892
+ "motionTrigger.getStatus": [{
102893
+ name: "deviceId",
102894
+ form: "single",
102895
+ optional: false
102896
+ }],
102556
102897
  "motionTrigger.setMotionTrigger": [{
102557
102898
  name: "deviceId",
102558
102899
  form: "single",
@@ -102563,6 +102904,11 @@ Object.freeze({
102563
102904
  form: "single",
102564
102905
  optional: false
102565
102906
  }],
102907
+ "motionZones.getStatus": [{
102908
+ name: "deviceId",
102909
+ form: "single",
102910
+ optional: false
102911
+ }],
102566
102912
  "motionZones.setZone": [{
102567
102913
  name: "deviceId",
102568
102914
  form: "single",
@@ -102573,6 +102919,11 @@ Object.freeze({
102573
102919
  form: "single",
102574
102920
  optional: false
102575
102921
  }],
102922
+ "nativeObjectDetection.getStatus": [{
102923
+ name: "deviceId",
102924
+ form: "single",
102925
+ optional: false
102926
+ }],
102576
102927
  "nativeObjectDetection.setEnabled": [{
102577
102928
  name: "deviceId",
102578
102929
  form: "single",
@@ -102588,6 +102939,11 @@ Object.freeze({
102588
102939
  form: "single",
102589
102940
  optional: false
102590
102941
  }],
102942
+ "navigation.getStatus": [{
102943
+ name: "deviceId",
102944
+ form: "single",
102945
+ optional: false
102946
+ }],
102591
102947
  "navigation.goToPoint": [{
102592
102948
  name: "deviceId",
102593
102949
  form: "single",
@@ -102633,6 +102989,11 @@ Object.freeze({
102633
102989
  form: "single",
102634
102990
  optional: false
102635
102991
  }],
102992
+ "networkLink.getStatus": [{
102993
+ name: "deviceId",
102994
+ form: "single",
102995
+ optional: false
102996
+ }],
102636
102997
  "networkQuality.getDeviceStats": [{
102637
102998
  name: "deviceId",
102638
102999
  form: "single",
@@ -102643,6 +103004,11 @@ Object.freeze({
102643
103004
  form: "single",
102644
103005
  optional: false
102645
103006
  }],
103007
+ "notificationRules.getAlarmSensors": [{
103008
+ name: "deviceIds",
103009
+ form: "array",
103010
+ optional: false
103011
+ }],
102646
103012
  "notificationRules.setDeviceMuted": [{
102647
103013
  name: "deviceId",
102648
103014
  form: "single",
@@ -102653,11 +103019,26 @@ Object.freeze({
102653
103019
  form: "single",
102654
103020
  optional: false
102655
103021
  }],
103022
+ "notifier.getStatus": [{
103023
+ name: "deviceId",
103024
+ form: "single",
103025
+ optional: false
103026
+ }],
102656
103027
  "notifier.send": [{
102657
103028
  name: "deviceId",
102658
103029
  form: "single",
102659
103030
  optional: false
102660
103031
  }],
103032
+ "numericSensor.getStatus": [{
103033
+ name: "deviceId",
103034
+ form: "single",
103035
+ optional: false
103036
+ }],
103037
+ "osd.getStatus": [{
103038
+ name: "deviceId",
103039
+ form: "single",
103040
+ optional: false
103041
+ }],
102661
103042
  "osd.setOverlay": [{
102662
103043
  name: "deviceId",
102663
103044
  form: "single",
@@ -102717,6 +103098,11 @@ Object.freeze({
102717
103098
  form: "single",
102718
103099
  optional: false
102719
103100
  }],
103101
+ "petFeeder.getStatus": [{
103102
+ name: "deviceId",
103103
+ form: "single",
103104
+ optional: false
103105
+ }],
102720
103106
  "petFeeder.markFoodReplenished": [{
102721
103107
  name: "deviceId",
102722
103108
  form: "single",
@@ -102752,6 +103138,11 @@ Object.freeze({
102752
103138
  form: "single",
102753
103139
  optional: false
102754
103140
  }],
103141
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
103142
+ name: "deviceId",
103143
+ form: "single",
103144
+ optional: false
103145
+ }],
102755
103146
  "pipelineAnalytics.clearTrackRelation": [{
102756
103147
  name: "deviceId",
102757
103148
  form: "single",
@@ -102792,6 +103183,16 @@ Object.freeze({
102792
103183
  form: "single",
102793
103184
  optional: false
102794
103185
  }],
103186
+ "pipelineAnalytics.getDeviceLiveContribution": [{
103187
+ name: "deviceId",
103188
+ form: "single",
103189
+ optional: false
103190
+ }],
103191
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
103192
+ name: "deviceId",
103193
+ form: "single",
103194
+ optional: false
103195
+ }],
102795
103196
  "pipelineAnalytics.getEventDensity": [{
102796
103197
  name: "deviceId",
102797
103198
  form: "single",
@@ -103007,6 +103408,11 @@ Object.freeze({
103007
103408
  form: "single",
103008
103409
  optional: true
103009
103410
  }],
103411
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
103412
+ name: "deviceId",
103413
+ form: "single",
103414
+ optional: false
103415
+ }],
103010
103416
  "pipelineOrchestrator.assignAudio": [{
103011
103417
  name: "deviceId",
103012
103418
  form: "single",
@@ -103052,6 +103458,16 @@ Object.freeze({
103052
103458
  form: "single",
103053
103459
  optional: false
103054
103460
  }],
103461
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
103462
+ name: "deviceId",
103463
+ form: "single",
103464
+ optional: false
103465
+ }],
103466
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
103467
+ name: "deviceId",
103468
+ form: "single",
103469
+ optional: false
103470
+ }],
103055
103471
  "pipelineOrchestrator.getPipelineAssignment": [{
103056
103472
  name: "deviceId",
103057
103473
  form: "single",
@@ -103172,11 +103588,31 @@ Object.freeze({
103172
103588
  form: "single",
103173
103589
  optional: true
103174
103590
  }],
103591
+ "powerMeter.getStatus": [{
103592
+ name: "deviceId",
103593
+ form: "single",
103594
+ optional: false
103595
+ }],
103596
+ "presence.getStatus": [{
103597
+ name: "deviceId",
103598
+ form: "single",
103599
+ optional: false
103600
+ }],
103601
+ "pressureSensor.getStatus": [{
103602
+ name: "deviceId",
103603
+ form: "single",
103604
+ optional: false
103605
+ }],
103175
103606
  "privacyMask.getOptions": [{
103176
103607
  name: "deviceId",
103177
103608
  form: "single",
103178
103609
  optional: false
103179
103610
  }],
103611
+ "privacyMask.getStatus": [{
103612
+ name: "deviceId",
103613
+ form: "single",
103614
+ optional: false
103615
+ }],
103180
103616
  "privacyMask.setAudioEnabled": [{
103181
103617
  name: "deviceId",
103182
103618
  form: "single",
@@ -103227,6 +103663,11 @@ Object.freeze({
103227
103663
  form: "single",
103228
103664
  optional: false
103229
103665
  }],
103666
+ "ptz.getStatus": [{
103667
+ name: "deviceId",
103668
+ form: "single",
103669
+ optional: false
103670
+ }],
103230
103671
  "ptz.goHome": [{
103231
103672
  name: "deviceId",
103232
103673
  form: "single",
@@ -103317,6 +103758,11 @@ Object.freeze({
103317
103758
  form: "single",
103318
103759
  optional: false
103319
103760
  }],
103761
+ "recordingArchive.applyDeviceSettingsPatch": [{
103762
+ name: "deviceId",
103763
+ form: "single",
103764
+ optional: false
103765
+ }],
103320
103766
  "recordingArchive.deleteFootprint": [{
103321
103767
  name: "deviceId",
103322
103768
  form: "single",
@@ -103337,6 +103783,21 @@ Object.freeze({
103337
103783
  form: "single",
103338
103784
  optional: false
103339
103785
  }],
103786
+ "recordingArchive.getDeviceLiveContribution": [{
103787
+ name: "deviceId",
103788
+ form: "single",
103789
+ optional: false
103790
+ }],
103791
+ "recordingArchive.getDeviceSettingsContribution": [{
103792
+ name: "deviceId",
103793
+ form: "single",
103794
+ optional: false
103795
+ }],
103796
+ "recordingArchive.getStatus": [{
103797
+ name: "deviceId",
103798
+ form: "single",
103799
+ optional: false
103800
+ }],
103340
103801
  "recordingArchive.listOpsLog": [{
103341
103802
  name: "deviceId",
103342
103803
  form: "single",
@@ -103422,6 +103883,11 @@ Object.freeze({
103422
103883
  form: "single",
103423
103884
  optional: false
103424
103885
  }],
103886
+ "recordingOnboard.getStatus": [{
103887
+ name: "deviceId",
103888
+ form: "single",
103889
+ optional: false
103890
+ }],
103425
103891
  "recordingOnboard.setSettings": [{
103426
103892
  name: "deviceId",
103427
103893
  form: "single",
@@ -103452,6 +103918,11 @@ Object.freeze({
103452
103918
  form: "single",
103453
103919
  optional: false
103454
103920
  }],
103921
+ "sceneMonitor.getStatus": [{
103922
+ name: "deviceId",
103923
+ form: "single",
103924
+ optional: false
103925
+ }],
103455
103926
  "sceneMonitor.listScenes": [{
103456
103927
  name: "deviceId",
103457
103928
  form: "single",
@@ -103477,6 +103948,11 @@ Object.freeze({
103477
103948
  form: "single",
103478
103949
  optional: false
103479
103950
  }],
103951
+ "scriptRunner.getStatus": [{
103952
+ name: "deviceId",
103953
+ form: "single",
103954
+ optional: false
103955
+ }],
103480
103956
  "scriptRunner.run": [{
103481
103957
  name: "deviceId",
103482
103958
  form: "single",
@@ -103487,11 +103963,31 @@ Object.freeze({
103487
103963
  form: "single",
103488
103964
  optional: false
103489
103965
  }],
103966
+ "smoke.getStatus": [{
103967
+ name: "deviceId",
103968
+ form: "single",
103969
+ optional: false
103970
+ }],
103971
+ "snapshot.applyDeviceSettingsPatch": [{
103972
+ name: "deviceId",
103973
+ form: "single",
103974
+ optional: false
103975
+ }],
103490
103976
  "snapshot.getDebugState": [{
103491
103977
  name: "deviceId",
103492
103978
  form: "single",
103493
103979
  optional: false
103494
103980
  }],
103981
+ "snapshot.getDeviceLiveContribution": [{
103982
+ name: "deviceId",
103983
+ form: "single",
103984
+ optional: false
103985
+ }],
103986
+ "snapshot.getDeviceSettingsContribution": [{
103987
+ name: "deviceId",
103988
+ form: "single",
103989
+ optional: false
103990
+ }],
103495
103991
  "snapshot.getSnapshot": [{
103496
103992
  name: "deviceId",
103497
103993
  form: "single",
@@ -103508,6 +104004,11 @@ Object.freeze({
103508
104004
  form: "array",
103509
104005
  optional: false
103510
104006
  }],
104007
+ "snapshot.getStatus": [{
104008
+ name: "deviceId",
104009
+ form: "single",
104010
+ optional: false
104011
+ }],
103511
104012
  "snapshot.invalidateCache": [{
103512
104013
  name: "deviceId",
103513
104014
  form: "single",
@@ -103518,6 +104019,11 @@ Object.freeze({
103518
104019
  form: "single",
103519
104020
  optional: false
103520
104021
  }],
104022
+ "streamBroker.applyDeviceSettingsPatch": [{
104023
+ name: "deviceId",
104024
+ form: "single",
104025
+ optional: false
104026
+ }],
103521
104027
  "streamBroker.assignProfile": [{
103522
104028
  name: "deviceId",
103523
104029
  form: "single",
@@ -103533,6 +104039,16 @@ Object.freeze({
103533
104039
  form: "single",
103534
104040
  optional: false
103535
104041
  }],
104042
+ "streamBroker.getDeviceLiveContribution": [{
104043
+ name: "deviceId",
104044
+ form: "single",
104045
+ optional: false
104046
+ }],
104047
+ "streamBroker.getDeviceSettingsContribution": [{
104048
+ name: "deviceId",
104049
+ form: "single",
104050
+ optional: false
104051
+ }],
103536
104052
  "streamBroker.getStreamWithCodec": [{
103537
104053
  name: "deviceId",
103538
104054
  form: "single",
@@ -103593,16 +104109,46 @@ Object.freeze({
103593
104109
  form: "single",
103594
104110
  optional: false
103595
104111
  }],
104112
+ "streamParams.getStatus": [{
104113
+ name: "deviceId",
104114
+ form: "single",
104115
+ optional: false
104116
+ }],
103596
104117
  "streamParams.setProfile": [{
103597
104118
  name: "deviceId",
103598
104119
  form: "single",
103599
104120
  optional: false
103600
104121
  }],
104122
+ "switch.getStatus": [{
104123
+ name: "deviceId",
104124
+ form: "single",
104125
+ optional: false
104126
+ }],
103601
104127
  "switch.setState": [{
103602
104128
  name: "deviceId",
103603
104129
  form: "single",
103604
104130
  optional: false
103605
104131
  }],
104132
+ "tamper.getStatus": [{
104133
+ name: "deviceId",
104134
+ form: "single",
104135
+ optional: false
104136
+ }],
104137
+ "temperatureSensor.getStatus": [{
104138
+ name: "deviceId",
104139
+ form: "single",
104140
+ optional: false
104141
+ }],
104142
+ "update.getStatus": [{
104143
+ name: "deviceId",
104144
+ form: "single",
104145
+ optional: false
104146
+ }],
104147
+ "vacuumControl.getStatus": [{
104148
+ name: "deviceId",
104149
+ form: "single",
104150
+ optional: false
104151
+ }],
103606
104152
  "vacuumControl.locate": [{
103607
104153
  name: "deviceId",
103608
104154
  form: "single",
@@ -103638,6 +104184,11 @@ Object.freeze({
103638
104184
  form: "single",
103639
104185
  optional: false
103640
104186
  }],
104187
+ "valve.getStatus": [{
104188
+ name: "deviceId",
104189
+ form: "single",
104190
+ optional: false
104191
+ }],
103641
104192
  "valve.open": [{
103642
104193
  name: "deviceId",
103643
104194
  form: "single",
@@ -103653,6 +104204,11 @@ Object.freeze({
103653
104204
  form: "single",
103654
104205
  optional: false
103655
104206
  }],
104207
+ "vibration.getStatus": [{
104208
+ name: "deviceId",
104209
+ form: "single",
104210
+ optional: false
104211
+ }],
103656
104212
  "videoclips.dialClipStream": [{
103657
104213
  name: "deviceId",
103658
104214
  form: "single",
@@ -103688,6 +104244,11 @@ Object.freeze({
103688
104244
  form: "single",
103689
104245
  optional: false
103690
104246
  }],
104247
+ "waterHeater.getStatus": [{
104248
+ name: "deviceId",
104249
+ form: "single",
104250
+ optional: false
104251
+ }],
103691
104252
  "waterHeater.setAway": [{
103692
104253
  name: "deviceId",
103693
104254
  form: "single",
@@ -103703,6 +104264,11 @@ Object.freeze({
103703
104264
  form: "single",
103704
104265
  optional: false
103705
104266
  }],
104267
+ "weather.getStatus": [{
104268
+ name: "deviceId",
104269
+ form: "single",
104270
+ optional: false
104271
+ }],
103706
104272
  "webrtcSession.addIceCandidate": [{
103707
104273
  name: "deviceId",
103708
104274
  form: "single",
@@ -104440,7 +105006,7 @@ var PreviewTextField = string().max(200);
104440
105006
  * Whether the notification's preview is a STILL or a short animation.
104441
105007
  *
104442
105008
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
104443
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
105009
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
104444
105010
  * night reads better as three seconds of motion than as one frame of it. Both
104445
105011
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
104446
105012
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -104578,6 +105144,7 @@ TimelapseRuleInputSchema.extend({
104578
105144
  createdAt: number(),
104579
105145
  updatedAt: number()
104580
105146
  });
105147
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
104581
105148
  object({
104582
105149
  /**
104583
105150
  * Fraction of the box's own size added on EACH side before cutting.