@camstack/addon-provider-petkit 0.2.116 → 0.2.117

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +892 -325
  2. package/dist/addon.mjs +892 -325
  3. package/package.json +1 -3
package/dist/addon.mjs CHANGED
@@ -1100,7 +1100,7 @@ var Nodepetkit = class {
1100
1100
  }
1101
1101
  };
1102
1102
  //#endregion
1103
- //#region ../types/dist/event-category-C5xZWqz6.mjs
1103
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
1104
1104
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
1105
1105
  EventCategory["SystemBoot"] = "system.boot";
1106
1106
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -1633,6 +1633,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
1633
1633
  */
1634
1634
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
1635
1635
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
1636
+ /**
1637
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
1638
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
1639
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
1640
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
1641
+ * for a camera with no attached sensor). Providers must not emit
1642
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
1643
+ * keeps it so (camera-grid is a named, deferred exception).
1644
+ */
1636
1645
  EventCategory["ProviderMotion"] = "provider.motion";
1637
1646
  EventCategory["ProviderDetection"] = "provider.detection";
1638
1647
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -6471,7 +6480,7 @@ var ZodIssueCode = {
6471
6480
  var ZodFirstPartyTypeKind;
6472
6481
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6473
6482
  //#endregion
6474
- //#region ../types/dist/sleep-gU6hqv4_.mjs
6483
+ //#region ../types/dist/sleep-CDCONfkt.mjs
6475
6484
  /**
6476
6485
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6477
6486
  * window to float samples (D455).
@@ -8514,7 +8523,7 @@ function errMsg(err) {
8514
8523
  return String(err);
8515
8524
  }
8516
8525
  //#endregion
8517
- //#region ../types/dist/composition-Dq42XWp0.mjs
8526
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
8518
8527
  /**
8519
8528
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8520
8529
  *
@@ -8568,21 +8577,20 @@ function portable(target) {
8568
8577
  }
8569
8578
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
8570
8579
  /**
8571
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
8572
- * valutatore puro del suo FRONTE.
8580
+ * THE table "which boolean of this device type counts as HIGH", and the
8581
+ * pure evaluator of its EDGE.
8573
8582
  *
8574
- * Viveva dentro il builtin virtual-doorbell
8575
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
8576
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
8577
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
8578
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
8579
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
8580
- * SPOSTA qui e il doorbell la ri-esporta.
8583
+ * ONE table for everyone who asks "is this device HIGH?": the
8584
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
8585
+ * sensor markers, the orchestrator's camera-sensors bridge and
8586
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
8587
+ * A second copy would diverge at the first cap added, and the symptom — "the
8588
+ * sensor rings the doorbell but does not record" — is exactly D62.
8581
8589
  *
8582
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
8583
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
8584
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
8585
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
8590
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
8591
+ * two must not be unified: that one answers "what is the state WORD for a
8592
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
8593
+ * boolean's EDGE counts". Deliberately different vocabularies.
8586
8594
  */
8587
8595
  /**
8588
8596
  * Known binary / switch source caps → the boolean slice field whose
@@ -10191,22 +10199,22 @@ var CLASS_MAP_MACRO_TARGETS = [
10191
10199
  "package"
10192
10200
  ];
10193
10201
  /**
10194
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
10195
- * un operatore può selezionare.
10202
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
10203
+ * an operator can select.
10196
10204
  *
10197
- * Sono le tre offerte dallo step `object-detection`
10205
+ * They are the three offered by the `object-detection` step
10198
10206
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
10199
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
10200
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
10201
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
10202
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
10207
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
10208
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
10209
+ * `package-detection`, whose enablement is driven by zones, and offering the
10210
+ * same word twice has already made an operator turn on the COCO proxy
10203
10211
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
10204
10212
  *
10205
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
10206
- * dello step e una seconda volta come union `FirstLevelMacro`
10207
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
10208
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
10209
- * successiva.
10213
+ * ONE list. Before today the same three were hand-written in the step's offer
10214
+ * and a second time as the union `FirstLevelMacro`
10215
+ * (`types/detection.ts`); a third copy for the recording trigger
10216
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
10217
+ * invisible.
10210
10218
  */
10211
10219
  var FIRST_LEVEL_MACRO_CLASSES = [
10212
10220
  "person",
@@ -10271,17 +10279,17 @@ var RecordingStorageModeSchema = _enum([
10271
10279
  "on-device-decision"
10272
10280
  ]);
10273
10281
  /**
10274
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
10275
- * tre offerte dallo step `object-detection`, da UNA lista
10282
+ * The macro classes that can open a recording window — the same
10283
+ * three offered by the `object-detection` step, from ONE list
10276
10284
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
10277
10285
  */
10278
10286
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
10279
10287
  /**
10280
- * True quando `values` non ripete un elemento.
10288
+ * True when `values` does not repeat an element.
10281
10289
  *
10282
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
10283
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
10284
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
10290
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
10291
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
10292
+ * would count its windows twice in `segmentMissedByMs`.
10285
10293
  */
10286
10294
  var noDuplicates = (values) => new Set(values).size === values.length;
10287
10295
  /** Which detectors trigger an `events`-mode band. */
@@ -10289,34 +10297,34 @@ var RecordingTriggersSchema = object({
10289
10297
  motion: boolean().optional(),
10290
10298
  audioThresholdDbfs: number().optional(),
10291
10299
  /**
10292
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
10293
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
10294
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
10295
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
10300
+ * The macro classes whose detection opens a window. ABSENT = the source
10301
+ * is not listened to; an EMPTY array is rejected, because "events band, object
10302
+ * trigger on, no class" is the same shape "enabled and records
10303
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
10296
10304
  *
10297
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
10298
- * quelle che hanno attraversato `enabledMacroClasses`, i
10299
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
10300
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
10301
- * finestre — vedi `recorder/object-trigger.ts`.
10305
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
10306
+ * those that went through `enabledMacroClasses`, the
10307
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
10308
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
10309
+ * windows — see `recorder/object-trigger.ts`.
10302
10310
  */
10303
10311
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
10304
10312
  /**
10305
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
10306
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
10313
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
10314
+ * is not listened to; an empty array is rejected for the same reason as
10307
10315
  * `objectClasses`.
10308
10316
  *
10309
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
10310
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
10311
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
10312
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
10313
- * device (D12) — mai un elenco globale di cap.
10317
+ * These are SOURCE device ids, not cameras: the band names them, so the
10318
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
10319
+ * does no RPC. The OFFER from which the operator picks them is another question, and
10320
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
10321
+ * device (D12) — never a global list of caps.
10314
10322
  *
10315
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
10316
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
10317
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
10318
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
10319
- * registrare.
10323
+ * What "high" means depends on the device TYPE and is not decided here:
10324
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
10325
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
10326
+ * the level: a contact found already open at runner restart does not
10327
+ * record.
10320
10328
  */
10321
10329
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
10322
10330
  });
@@ -11393,7 +11401,7 @@ var DecoderSessionConfigSchema = object({
11393
11401
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
11394
11402
  * thing: the logging settings document on the `system` cap. Two authorities
11395
11403
  * over the values is the exact defect
11396
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
11404
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
11397
11405
  * remove; re-introducing it from the cure side would be grotesque.
11398
11406
  *
11399
11407
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -13104,7 +13112,7 @@ var BrokerStatusEnum = _enum([
13104
13112
  "unreachable",
13105
13113
  "error"
13106
13114
  ]);
13107
- var BrokerInfoSchema$1 = object({
13115
+ var BrokerInfoSchema = object({
13108
13116
  /** Stable broker id. Persisted; survives addon restarts. */
13109
13117
  id: string(),
13110
13118
  /** Addon id of the provider that OWNS this broker.
@@ -13237,7 +13245,7 @@ var GetStateInputSchema = object({
13237
13245
  * HA: entity_id (returns the cached entity state). */
13238
13246
  key: string()
13239
13247
  });
13240
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
13248
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
13241
13249
  kind: "mutation",
13242
13250
  auth: "admin"
13243
13251
  }), method(RemoveInputSchema, _void(), {
@@ -14948,7 +14956,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
14948
14956
  *
14949
14957
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
14950
14958
  * was wrong — corrected 2026-08-26 after the hop map
14951
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
14959
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
14952
14960
  * There is **no Zod parse at all** between the door and the engine: the
14953
14961
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
14954
14962
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -15828,7 +15836,17 @@ var SiteZoneSchema = object({
15828
15836
  var ProviderStatusSchema = object({
15829
15837
  connected: boolean(),
15830
15838
  deviceCount: number(),
15831
- error: string().optional()
15839
+ error: string().optional(),
15840
+ /**
15841
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
15842
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
15843
+ * which every provider bundles, so only a provider BUILT from D696-amended
15844
+ * code says it. ABSENT means an older provider that may still write it (raw
15845
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
15846
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
15847
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
15848
+ */
15849
+ motionSliceWriter: literal("orchestrator").optional()
15832
15850
  });
15833
15851
  object({
15834
15852
  externalId: string(),
@@ -16707,109 +16725,10 @@ method(object({
16707
16725
  deviceIds: array(number()).readonly(),
16708
16726
  caps: array(string()).readonly().optional()
16709
16727
  }), record(string(), record(string(), unknown().nullable())));
16710
- /**
16711
- * Doorbell button cap. Two kinds of providers coexist behind this cap
16712
- * name (same pattern as `snapshot`):
16713
- *
16714
- * - **Native** providers: registered per-device by device-driver
16715
- * addons via `ctx.registerNativeCap` — either on a
16716
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
16717
- * or directly on the camera (Reolink registers at camera level).
16718
- * Emits an `onPressed` event every time the firmware pushes a
16719
- * ring; status tracks the last press and a pressCount since start
16720
- * (diagnostic).
16721
- *
16722
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
16723
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
16724
- * device (contact / switch / event-emitter …) into a doorbell for
16725
- * a camera. `defaultActive: false` — the operator explicitly binds
16726
- * it per camera in the device-bindings UI, then picks the source
16727
- * device + trigger in the per-device settings.
16728
- *
16729
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
16730
- * — subscribers listening at the camera level receive ring events
16731
- * with `via[]` populated. No code on the parent needed.
16732
- */
16733
- var DoorbellStatusSchema = object({
16734
- /** Ms epoch of the last press. null = never observed since this provider started. */
16735
- lastPressedAt: number().nullable(),
16736
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
16737
- pressCountSinceStart: number()
16738
- });
16739
- var DoorbellPressEventSchema = object({
16740
- deviceId: number(),
16741
- timestamp: number()
16742
- });
16743
- /**
16744
- * The `doorbell-source` extension slot's editable value (D648): the camera's
16745
- * virtual-doorbell trigger devices, exactly what the wrapper's
16746
- * `doorbellSources` persists (as `{ deviceId }` records).
16747
- */
16748
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
16749
- /**
16750
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
16751
- * doorbell, owned by the `virtual-doorbell` wrapper over its
16752
- * `doorbellSources` store (D648). A source rings when one of its
16753
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
16754
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
16755
- * reports it, it never writes it.
16756
- */
16757
- var DOORBELL_SOURCE_SLOT = {
16758
- id: "doorbell-source",
16759
- label: "Doorbell trigger devices",
16760
- 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.",
16761
- shape: "association",
16762
- hostDeviceTypes: [DeviceType.Camera],
16763
- sourceCaps: SOURCE_CAPS,
16764
- cardinality: "many",
16765
- value: DoorbellSourceSlotValueSchema
16766
- };
16767
- var doorbellCapability = {
16768
- name: "doorbell",
16769
- scope: "device",
16770
- deviceNative: true,
16771
- mode: "singleton",
16772
- kind: "wrapper",
16773
- defaultActive: false,
16774
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
16775
- extensionSlots: [DOORBELL_SOURCE_SLOT],
16776
- methods: {},
16777
- events: {
16778
- /**
16779
- * Fires once per physical press. Reolink delivers via Baichuan
16780
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
16781
- * release/duration — it's a pulse.
16782
- */
16783
- onPressed: {
16784
- data: DoorbellPressEventSchema,
16785
- fromState: {
16786
- field: "lastPressedAt",
16787
- on: "advance"
16788
- }
16789
- } },
16790
- status: {
16791
- schema: DoorbellStatusSchema,
16792
- kind: "push"
16793
- },
16794
- /**
16795
- * Runtime-state slice — last press timestamp + lifetime press count.
16796
- * Mirrored by the kernel and readable via
16797
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
16798
- * without subscribing.
16799
- */
16800
- runtimeState: DoorbellStatusSchema,
16801
- /**
16802
- * 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.
16803
- *
16804
- * See `RuntimeStateDurability`. Enforced by
16805
- * `scripts/check-runtime-state-durability.ts`.
16806
- */
16807
- durability: "restored"
16808
- };
16809
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
16810
- DeviceType.Camera, DeviceType.Camera;
16728
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
16729
+ DeviceType.Camera;
16811
16730
  /** A slot's editable value, discriminated on `slot`. */
16812
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
16731
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
16813
16732
  DeviceType.Camera;
16814
16733
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
16815
16734
  state: literal("unreachable"),
@@ -16846,10 +16765,11 @@ var ExtensionSlotSourceSchema = object({
16846
16765
  });
16847
16766
  /**
16848
16767
  * A DIFFERENT authority that gates whether the slot's sources do anything —
16849
- * reported read-only, named, never written through this contract (D62). The
16850
- * virtual doorbell's sources ring only while the wrapper is bound to the
16851
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
16852
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
16768
+ * reported read-only, named, never written through this contract (D62) — e.g.
16769
+ * a slot whose sources act only while a wrapper is bound to the host, a
16770
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
16771
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
16772
+ * not be read; it is not "inactive" (D315).
16853
16773
  */
16854
16774
  var ExtensionSlotActivationSchema = object({
16855
16775
  state: _enum([
@@ -16865,7 +16785,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
16865
16785
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
16866
16786
  slotRef: string(),
16867
16787
  slot: ExtensionSlotIdSchema,
16868
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
16788
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
16869
16789
  authority: string(),
16870
16790
  activation: ExtensionSlotActivationSchema.nullable(),
16871
16791
  value: ExtensionSlotValueSchema,
@@ -17143,7 +17063,7 @@ method(object({
17143
17063
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
17144
17064
  * ends in a log line, and a log line is the thing the operator asked to stop
17145
17065
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
17146
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
17066
+ * 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
17147
17067
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
17148
17068
  * media blackout were both diagnosed. The counters stay; this is where they can
17149
17069
  * be READ.
@@ -18519,7 +18439,7 @@ var BrokerStatusSchema$1 = _enum([
18519
18439
  "unreachable",
18520
18440
  "tls-error"
18521
18441
  ]);
18522
- var BrokerInfoSchema = object({
18442
+ var BrokerInfoSchema$1 = object({
18523
18443
  id: string(),
18524
18444
  name: string(),
18525
18445
  url: string(),
@@ -18582,7 +18502,7 @@ var StatusSchema = object({
18582
18502
  brokerCount: number(),
18583
18503
  embeddedRunning: boolean()
18584
18504
  });
18585
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
18505
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
18586
18506
  kind: "mutation",
18587
18507
  auth: "admin"
18588
18508
  }), method(IdInputSchema, _void(), {
@@ -20796,78 +20716,16 @@ var NcRuleInputSchema = object({
20796
20716
  */
20797
20717
  confirm: NcConfirmSchema.optional(),
20798
20718
  /**
20799
- * WAIT for face/plate recognition before saying anything.
20800
- *
20801
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
20802
- * send; the identity is neither. A face is confirmed after `confirmFrames`
20803
- * agreeing observations — p50 **11.4 s** after the track was first seen,
20804
- * measured on this hub — and an `immediate` rule enqueues on the first object
20805
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
20806
- * immediate path, and no amount of media re-resolution fixes a sentence.
20807
- *
20808
- * Only two honest answers exist, and this flag picks between them. It has
20809
- * effect ONLY on a rule that declares a recognition scope
20810
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
20811
- * other rule there is nothing to wait for and the flag is inert.
20812
- *
20813
- * | value | what happens |
20814
- * | --- | --- |
20815
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
20816
- * | 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) |
20817
- *
20818
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
20819
- * on the addon cap path, and absent has to keep meaning exactly what every
20820
- * rule authored before this field meant.
20821
- *
20822
- * The cost of `true` is stated here because the editor states it too: a rule
20823
- * that waits also inherits track-close SEMANTICS — its `zones` condition
20824
- * tests every zone the track visited and a `crossing` condition can no longer
20825
- * be satisfied, because a closed track carries no crossing.
20719
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
20720
+ * seconds; the rule sends ONE message when the window closes — early, once every
20721
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
20722
+ * the rule matched, with one mosaic tile per subject.
20723
+ * Absent = plain immediate (one message per track, at the first match).
20724
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
20725
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
20726
+ * path does not run Zod defaults.
20826
20727
  */
20827
- waitForEnhancement: boolean().optional(),
20828
- /**
20829
- * GROUP a burst of subjects into ONE notification that grows.
20830
- *
20831
- * Seconds of quiet after the last matching subject before the burst is
20832
- * considered over. While it is open, the first subject enqueues immediately —
20833
- * **exactly as today, with no added latency** — and every real growth (a new
20834
- * subject, or a name confirmed on one already in it) REPLACES that
20835
- * notification with an updated one naming everybody. The push carries the
20836
- * group's own coalescing tag, so the phone replaces rather than stacks.
20837
- *
20838
- * `0` / absent = off, and off is today's behaviour byte for byte.
20839
- *
20840
- * ### Why an idle cutoff and not a window
20841
- *
20842
- * The measured seven-person arrival on device 590 spans 110 s with every
20843
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
20844
- * idle cutoff holds it as one and ends it when the arrival actually ends.
20845
- * 30 s is a widely shipped value for the same decision.
20846
- *
20847
- * ### What it replaces
20848
- *
20849
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
20850
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
20851
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
20852
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
20853
- * A group collapses the same volume by MERGING, so the cooldown becomes a
20854
- * budget over GROUPS — which is what it always meant — and a growth is never
20855
- * throttled by the window its own first member spent.
20856
- *
20857
- * ### Interaction with {@link waitForEnhancement}
20858
- *
20859
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
20860
- * TRACK CLOSE, so with both set the group is opened by the first member to
20861
- * CLOSE — already carrying its name — and grows as later members close. That
20862
- * is later, and complete. With grouping alone the group opens on the first
20863
- * object event and picks up names as they are confirmed, through the growth
20864
- * path. Neither combination fires twice for one subject.
20865
- *
20866
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
20867
- * on the addon cap path, so absent must keep meaning what it meant before this
20868
- * field existed.
20869
- */
20870
- groupIdleSec: number().int().min(0).max(600).optional()
20728
+ groupingSec: number().int().min(5).max(60).optional()
20871
20729
  });
20872
20730
  /**
20873
20731
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -20915,9 +20773,10 @@ var NcRuleClearableKeySchema = _enum([
20915
20773
  "targetUsers",
20916
20774
  "snoozeOptions",
20917
20775
  "snoozeAllowGlobal",
20918
- "waitForEnhancement",
20919
20776
  "actions",
20920
20777
  "confirm",
20778
+ "groupingSec",
20779
+ "waitForEnhancement",
20921
20780
  "groupIdleSec"
20922
20781
  ]);
20923
20782
  var NcRuleUpdateInputSchema = object({
@@ -20939,9 +20798,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20939
20798
  */
20940
20799
  disabledTargetIds: array(string()).default([])
20941
20800
  });
20801
+ /**
20802
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20803
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
20804
+ * job is not an open state, and the alarm stays instant.
20805
+ */
20806
+ var NcStateSummarySectionIdSchema = _enum([
20807
+ "device-state",
20808
+ "streams",
20809
+ "battery",
20810
+ "consumables",
20811
+ "tanks",
20812
+ "detection-blind",
20813
+ "nodes",
20814
+ "addons",
20815
+ "updates"
20816
+ ]);
20942
20817
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
20943
20818
  var NcStateSummaryPreviewSectionSchema = object({
20944
- id: string(),
20819
+ id: NcStateSummarySectionIdSchema,
20945
20820
  status: _enum(["read", "unavailable"]),
20946
20821
  items: number().int().nonnegative(),
20947
20822
  reason: string().optional()
@@ -20951,7 +20826,7 @@ var NcStateSummaryPreviewSectionSchema = object({
20951
20826
  * a `rule` split (no `section`), one section's on a `section` split.
20952
20827
  */
20953
20828
  var NcStateSummaryPreviewRowSchema = object({
20954
- section: string().optional(),
20829
+ section: NcStateSummarySectionIdSchema.optional(),
20955
20830
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
20956
20831
  title: string(),
20957
20832
  text: string(),
@@ -21388,6 +21263,29 @@ object({
21388
21263
  firstAt: number(),
21389
21264
  lastAt: number()
21390
21265
  });
21266
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
21267
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
21268
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
21269
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
21270
+ var NcAlarmModeDelaysListSchema = array(object({
21271
+ mode: AlarmArmModeSchema,
21272
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
21273
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
21274
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
21275
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
21276
+ var NcAlarmModeDelaysEditListSchema = array(object({
21277
+ mode: AlarmArmModeSchema,
21278
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21279
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21280
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
21281
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
21282
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
21283
+ var NcAlarmNonBlockingEditSchema = object({
21284
+ mode: AlarmArmModeSchema,
21285
+ deviceId: number().int().positive(),
21286
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
21287
+ nonBlocking: boolean()
21288
+ });
21391
21289
  /**
21392
21290
  * The per-mode lists, at most one per mode. Two lists for one mode have no
21393
21291
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -21396,10 +21294,10 @@ object({
21396
21294
  var NcAlarmNonBlockingListSchema = array(object({
21397
21295
  mode: AlarmArmModeSchema,
21398
21296
  deviceIds: array(number().int()).max(200)
21399
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
21297
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
21400
21298
  /**
21401
- * The three durations the panel's state machine runs on, who hears about its
21402
- * transitions, and which openings each mode tolerates.
21299
+ * The three durations — global, and per mode since D697 — the panel's state
21300
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
21403
21301
  *
21404
21302
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
21405
21303
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -21409,15 +21307,15 @@ var NcAlarmNonBlockingListSchema = array(object({
21409
21307
  */
21410
21308
  var NcAlarmSettingsSchema = object({
21411
21309
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
21412
- exitDelaySec: number().int().min(0).max(600),
21310
+ exitDelaySec: NcAlarmDelaySecSchema,
21413
21311
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
21414
- entryDelaySec: number().int().min(0).max(600),
21312
+ entryDelaySec: NcAlarmDelaySecSchema,
21415
21313
  /**
21416
21314
  * How long `triggered` lasts before the panel re-arms itself.
21417
21315
  * **0 = until an operator disarms it** — the behaviour before this field
21418
21316
  * existed, and therefore what an untouched install keeps doing.
21419
21317
  */
21420
- triggeredDurationSec: number().int().min(0).max(3600),
21318
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
21421
21319
  /**
21422
21320
  * Deprecated by D630 — every transition is announced. Parsed, never read;
21423
21321
  * remove after one release. Optional so an older admin's patch (which still
@@ -21440,17 +21338,30 @@ var NcAlarmSettingsSchema = object({
21440
21338
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
21441
21339
  * parses as "every opening blocks" — the behaviour it was written under.
21442
21340
  */
21443
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
21341
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
21342
+ /**
21343
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
21344
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
21345
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
21346
+ */
21347
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
21444
21348
  });
21445
21349
  /**
21446
21350
  * Every field optional — a tab edits one control at a time.
21447
21351
  *
21448
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
21449
- * remove an inner `.default()`, so a patch that never named the field would
21450
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
21451
- * (the same trap {@link NcRulePatchSchema} documents).
21352
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
21353
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
21354
+ * named the field would parse to `[]` and wipe every mode's list on an
21355
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
21356
+ * `modeDelays` means EDITS, not the stored overrides.
21452
21357
  */
21453
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
21358
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
21359
+ nonBlocking: NcAlarmNonBlockingListSchema,
21360
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
21361
+ modeDelays: NcAlarmModeDelaysEditListSchema,
21362
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
21363
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
21364
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
21454
21365
  /**
21455
21366
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
21456
21367
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -21550,6 +21461,28 @@ var NcAlarmConfigSchema = object({
21550
21461
  */
21551
21462
  live: NcAlarmLiveSchema.optional()
21552
21463
  });
21464
+ var NcAlarmSensorReadingSchema = _enum([
21465
+ "open",
21466
+ "closed",
21467
+ "unknown",
21468
+ "not-opening"
21469
+ ]);
21470
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
21471
+ var NcAlarmSensorStateSchema = object({
21472
+ deviceId: number().int().positive(),
21473
+ reading: NcAlarmSensorReadingSchema,
21474
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
21475
+ state: string().nullable(),
21476
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
21477
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
21478
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
21479
+ online: boolean().nullable()
21480
+ });
21481
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
21482
+ var NcAlarmSensorsSchema = object({
21483
+ sensors: array(NcAlarmSensorStateSchema),
21484
+ readAt: number().int().nonnegative()
21485
+ });
21553
21486
  /**
21554
21487
  * ONE rule's demand on ONE camera's clip ring.
21555
21488
  *
@@ -21640,7 +21573,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
21640
21573
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
21641
21574
  kind: "mutation",
21642
21575
  auth: "admin"
21643
- });
21576
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
21644
21577
  /**
21645
21578
  * Zod schemas for persisted record types.
21646
21579
  *
@@ -21987,12 +21920,26 @@ var CameraSensorRefSchema = object({
21987
21920
  function cameraSensorRefKey(ref) {
21988
21921
  return `${ref.addonId}/${ref.stableId}`;
21989
21922
  }
21990
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
21991
- var CameraSensorsModeSchema = _enum(["in-addition"]);
21992
- var CameraSensorsConfigSchema = object({
21993
- mode: CameraSensorsModeSchema,
21994
- sensors: array(CameraSensorRefSchema).min(1).max(8)
21995
- }).superRefine((value, ctx) => {
21923
+ /**
21924
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
21925
+ * `replace`: its motion is the camera's, and while one is READY the camera's
21926
+ * own motion no longer counts on its own. `confirm`: while one is READY the
21927
+ * camera's own motion counts only while a confirm sensor is active — with or
21928
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
21929
+ */
21930
+ var CameraSensorModeSchema = _enum([
21931
+ "in-addition",
21932
+ "confirm",
21933
+ "replace"
21934
+ ]);
21935
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
21936
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
21937
+ /**
21938
+ * A camera's attached sensors. A CS-1 row carried an envelope
21939
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
21940
+ * what the write stores (D672 rule 3), so it is never written again.
21941
+ */
21942
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
21996
21943
  const seen = /* @__PURE__ */ new Set();
21997
21944
  value.sensors.forEach((ref, index) => {
21998
21945
  const key = cameraSensorRefKey(ref);
@@ -22004,39 +21951,41 @@ var CameraSensorsConfigSchema = object({
22004
21951
  seen.add(key);
22005
21952
  });
22006
21953
  });
22007
- var RefFields = {
21954
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
21955
+ var AttachmentFields = {
22008
21956
  addonId: string(),
22009
- stableId: string()
21957
+ stableId: string(),
21958
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
22010
21959
  };
22011
21960
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
22012
21961
  object({
22013
- ...RefFields,
21962
+ ...AttachmentFields,
22014
21963
  state: literal("ready"),
22015
21964
  deviceId: number(),
22016
21965
  name: string(),
22017
21966
  caps: array(string()).readonly()
22018
21967
  }),
22019
21968
  object({
22020
- ...RefFields,
21969
+ ...AttachmentFields,
22021
21970
  state: literal("offline"),
22022
21971
  deviceId: number(),
22023
21972
  name: string(),
22024
21973
  reason: _enum(["offline", "disabled"])
22025
21974
  }),
22026
21975
  object({
22027
- ...RefFields,
21976
+ ...AttachmentFields,
22028
21977
  state: literal("missing"),
22029
21978
  reason: string()
22030
21979
  }),
22031
21980
  object({
22032
- ...RefFields,
21981
+ ...AttachmentFields,
22033
21982
  state: literal("unsupported"),
22034
21983
  deviceId: number(),
22035
21984
  name: string(),
22036
21985
  reason: string()
22037
21986
  }),
22038
21987
  object({
22039
- ...RefFields,
21988
+ ...AttachmentFields,
22040
21989
  state: literal("unreadable"),
22041
21990
  reason: string()
22042
21991
  })
@@ -22049,17 +21998,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
22049
21998
  * say.
22050
21999
  */
22051
22000
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
22001
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
22002
+ var CameraOwnMotionSchema = _enum([
22003
+ "always",
22004
+ "when-confirmed",
22005
+ "never"
22006
+ ]);
22007
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
22008
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
22009
+ /**
22010
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
22011
+ * never the effective value. The camera's `motion` slice is the effective one,
22012
+ * so a view of the camera's own row reads this.
22013
+ * - `atMs`: when the bridge received the camera's last own edge.
22014
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
22015
+ * AND it is younger than the window the bridge counts the camera's own motion
22016
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
22017
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
22018
+ * within the window; a status read is a snapshot, so a live view re-asks.
22019
+ * Absent = this orchestrator has not received the camera's own motion since it
22020
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
22021
+ */
22022
+ var CameraRawLevelSchema = object({
22023
+ detected: boolean(),
22024
+ atMs: number()
22025
+ });
22052
22026
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
22053
- object({ state: literal("not-configured") }),
22027
+ object({
22028
+ state: literal("not-configured"),
22029
+ cameraLevel: CameraRawLevelSchema.optional()
22030
+ }),
22054
22031
  object({
22055
22032
  state: literal("unreadable"),
22056
- reason: string()
22033
+ reason: string(),
22034
+ cameraLevel: CameraRawLevelSchema.optional()
22057
22035
  }),
22058
22036
  object({
22059
22037
  state: literal("configured"),
22060
- mode: CameraSensorsModeSchema,
22038
+ cameraLevel: CameraRawLevelSchema.optional(),
22061
22039
  sensors: array(CameraSensorAttachmentSchema).readonly(),
22062
- notForwarded: CameraSensorsNotForwardedSchema.optional()
22040
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
22041
+ cameraMotion: CameraOwnMotionSchema.optional(),
22042
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
22043
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
22063
22044
  })
22064
22045
  ]);
22065
22046
  Object.freeze({
@@ -22744,14 +22725,14 @@ var TrackSchema = object({
22744
22725
  * `derive-returned-null tile=standin`,
22745
22726
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
22746
22727
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
22747
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
22728
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
22748
22729
  * tile is a face/plate stand-in, a raster crop, or an icon.
22749
22730
  *
22750
22731
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
22751
22732
  * the TILE ranked below native, so a track whose thumbnail landed natively
22752
22733
  * while its key frame missed carried no reason at all — three of the four
22753
22734
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
22754
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
22735
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
22755
22736
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
22756
22737
  * lastFrame copy source`), so its absence is now on this line whatever the
22757
22738
  * tile ended up being.
@@ -22838,7 +22819,7 @@ var MotionEventSchema = object({
22838
22819
  /**
22839
22820
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
22840
22821
  * first entry is always `0`) of every genuine off→on transition the
22841
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
22822
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
22842
22823
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
22843
22824
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
22844
22825
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -23362,6 +23343,7 @@ var KeyEventSchema = object({
23362
23343
  bestEventId: string(),
23363
23344
  /** Track lifetime in ms (lastSeen - firstSeen). */
23364
23345
  windowMs: number().optional(),
23346
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
23365
23347
  ...TrackFlagFields,
23366
23348
  ...TrackRetrainFields
23367
23349
  });
@@ -25290,8 +25272,10 @@ var RunnerCameraConfigSchema = object({
25290
25272
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
25291
25273
  * analyzer providers) running on decoded frames in this runner.
25292
25274
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
25293
- * analytics). The provider emits ProviderMotion
25294
- * events; the orchestrator forwards to `reportMotion`.
25275
+ * analytics). The provider emits its raw push as `ProviderMotion`
25276
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
25277
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
25278
+ * `reportMotion`.
25295
25279
  */
25296
25280
  motionSources: MotionSourcesSchema.default(["analyzer"]),
25297
25281
  /**
@@ -25468,7 +25452,15 @@ var RunnerLocalLoadSchema = object({
25468
25452
  hasGpu: boolean(),
25469
25453
  inferenceBackend: string().optional(),
25470
25454
  cpuCores: number().optional()
25471
- })
25455
+ }),
25456
+ /**
25457
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
25458
+ * runner never writes it. ABSENT = a runner older than D696, which still
25459
+ * writes the slice from its phase machine; the orchestrator does not write
25460
+ * while any runner node is absent-or-unanswered, so one slice never has two
25461
+ * writers.
25462
+ */
25463
+ motionSliceWriter: literal("orchestrator").optional()
25472
25464
  });
25473
25465
  /**
25474
25466
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -28133,7 +28125,7 @@ var ClipPlaybackSchema = object({
28133
28125
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
28134
28126
  * time the camera is awake for its own reasons — is deliberately not a member:
28135
28127
  * it was proposed, it is free on the battery, and the operator declined it on
28136
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
28128
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
28137
28129
  * D558 "Considered and not taken").
28138
28130
  */
28139
28131
  var ClipWakeSchema = _enum(["authorised"]);
@@ -28394,7 +28386,7 @@ DeviceType.Camera, method(object({
28394
28386
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
28395
28387
  * assumed the answer was a fan-out over everything a camera has. The
28396
28388
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
28397
- * solo"* — so the list is asked of one provider at a time and there is
28389
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
28398
28390
  * nothing to filter out of it.
28399
28391
  */
28400
28392
  provider: string().min(1)
@@ -30997,6 +30989,70 @@ onStatusChanged: { data: object({
30997
30989
  * whether persisting is worth a SQLite commit. */
30998
30990
  volatileStateFields: ["lastChangedAt"]
30999
30991
  };
30992
+ var DoorbellStatusSchema = object({
30993
+ /** Ms epoch of the last press. null = never observed since this provider started. */
30994
+ lastPressedAt: number().nullable(),
30995
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
30996
+ pressCountSinceStart: number()
30997
+ });
30998
+ var DoorbellPressEventSchema = object({
30999
+ deviceId: number(),
31000
+ timestamp: number()
31001
+ });
31002
+ /**
31003
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
31004
+ * they are the same cap:
31005
+ *
31006
+ * - **Native** providers, registered per device by a driver addon through
31007
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
31008
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
31009
+ * camera level). They emit `onPressed` on every firmware ring.
31010
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
31011
+ * the cap, its `lastPressedAt` rising from the sources the operator
31012
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
31013
+ * from that field's advance (`fromState`).
31014
+ *
31015
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
31016
+ */
31017
+ var doorbellCapability = {
31018
+ name: "doorbell",
31019
+ scope: "device",
31020
+ deviceNative: true,
31021
+ mode: "singleton",
31022
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
31023
+ methods: {},
31024
+ events: {
31025
+ /**
31026
+ * Fires once per physical press. Reolink delivers via Baichuan
31027
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
31028
+ * release/duration — it's a pulse.
31029
+ */
31030
+ onPressed: {
31031
+ data: DoorbellPressEventSchema,
31032
+ fromState: {
31033
+ field: "lastPressedAt",
31034
+ on: "advance"
31035
+ }
31036
+ } },
31037
+ status: {
31038
+ schema: DoorbellStatusSchema,
31039
+ kind: "push"
31040
+ },
31041
+ /**
31042
+ * Runtime-state slice — last press timestamp + lifetime press count.
31043
+ * Mirrored by the kernel and readable via
31044
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
31045
+ * without subscribing.
31046
+ */
31047
+ runtimeState: DoorbellStatusSchema,
31048
+ /**
31049
+ * 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.
31050
+ *
31051
+ * See `RuntimeStateDurability`. Enforced by
31052
+ * `scripts/check-runtime-state-durability.ts`.
31053
+ */
31054
+ durability: "restored"
31055
+ };
31000
31056
  /**
31001
31057
  * Enum-state sensor — a string value picked from a finite option set.
31002
31058
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -33141,9 +33197,9 @@ var MotionStatusSchema = object({
33141
33197
  /** Ms epoch of the last detected-true observation. Null if never detected. */
33142
33198
  lastDetectedAt: number().nullable(),
33143
33199
  /**
33144
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
33145
- * `null` while false and on every `Sensor` device (D475) — see that
33146
- * constant's doc for the one-authority rule.
33200
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
33201
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
33202
+ * device (D475) — see that constant's doc for the one-authority rule.
33147
33203
  *
33148
33204
  * ## Reading this field still arms nothing
33149
33205
  *
@@ -33161,34 +33217,31 @@ var MotionStatusSchema = object({
33161
33217
  * `addon-export-alexa/src/motion-clear-hold.ts` and
33162
33218
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
33163
33219
  *
33164
- * ## Who writes it
33165
- *
33166
- * - **Cameras** — the runner's phase machine, `active → watching` on
33167
- * `cooldown_expired`, which then writes this slice with
33168
- * `detected: false` (`handlePhaseChanged` in
33169
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
33170
- * matters most for the sources that only ever push a rising one:
33171
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
33172
- * a false.
33173
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
33174
- * provider pushes the false itself, from the upstream system's own
33175
- * state change. No phase machine is involved.
33176
- *
33177
- * ### The phase machine is CANONICAL, not sole — and that is a defect
33178
- *
33179
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
33180
- * phase machine is the sole writer for a camera. It is not.
33181
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
33182
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
33183
- * Hikvision's comment says why: it read THIS docblock, agreed the
33184
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
33185
- * two authorities can disagree about one slice, which this repo
33186
- * forbids, and the doc said otherwise — which is worse than saying
33187
- * nothing, because it reads as verification.
33188
- *
33189
- * This predates D475 and is not fixed there: the fix touches every
33190
- * camera provider. Recorded in D475's Consequences. Do not restore the
33191
- * "sole writer" wording without also removing the other writers.
33220
+ * ## Who writes it (D696)
33221
+ *
33222
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
33223
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
33224
+ * `camera-sensors/motion-slice.ts`), alongside the effective
33225
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
33226
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
33227
+ * device activity, as the camera's `motionSources` counts them. A source
33228
+ * that never sends a clear falls one window after its last `true`.
33229
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
33230
+ * writes this slice (not even a boot seed), and neither does the runner's
33231
+ * phase machine: its phase is "a session is attached" for every on-motion
33232
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
33233
+ * A provider's `isDetected` answers from the hub's slice.
33234
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
33235
+ * imports) — the provider pushes both edges itself, from the upstream
33236
+ * system's own state change. That is the sensor's own fact.
33237
+ *
33238
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
33239
+ * `motion` slice; each sensor writer is a named exemption.
33240
+ *
33241
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
33242
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
33243
+ * it, every provider seeded it at boot, and every session left it
33244
+ * `detected: true` after its detach.
33192
33245
  */
33193
33246
  autoClearAfterMs: number().nullable()
33194
33247
  });
@@ -33260,11 +33313,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
33260
33313
  */
33261
33314
  runtimeState: MotionStatusSchema,
33262
33315
  /**
33263
- * Runtime-state durability: **session** — every writer of this slice
33316
+ * Runtime-state durability: **session** — the writer of this slice
33264
33317
  * writes only on an EDGE, so a restored `detected: true` would stay
33265
33318
  * frozen until the next one instead of being corrected. The next edge
33266
- * re-publishes the real state. (On who the writers are, and why there
33267
- * is more than one, see `autoClearAfterMs` above.)
33319
+ * re-publishes the real state, and the orchestrator re-publishes every
33320
+ * camera when it starts writing (D696; on who writes it, see
33321
+ * `autoClearAfterMs` above).
33268
33322
  *
33269
33323
  * See `RuntimeStateDurability`. Enforced by
33270
33324
  * `scripts/check-runtime-state-durability.ts`.
@@ -35647,8 +35701,7 @@ var ptzAutotrackCapability = {
35647
35701
  deviceNative: true,
35648
35702
  mode: "singleton",
35649
35703
  /**
35650
- * Two kinds of provider behind one name, the same shape `snapshot` and
35651
- * `doorbell` use:
35704
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
35652
35705
  *
35653
35706
  * - **Native**: the camera's own firmware autotrack, registered per device by
35654
35707
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -35656,7 +35709,7 @@ var ptzAutotrackCapability = {
35656
35709
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
35657
35710
  * which follows a subject with `ptz.move` pulses driven by the detection
35658
35711
  * pipeline. `defaultActive: false` — the operator binds it per camera in
35659
- * the bindings UI, exactly as `virtual-doorbell` is bound.
35712
+ * the bindings UI.
35660
35713
  *
35661
35714
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
35662
35715
  * one switch for the function either way. A camera never has both driving its
@@ -36331,7 +36384,7 @@ var ReadGopBytesResultSchema = object({
36331
36384
  /**
36332
36385
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
36333
36386
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
36334
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
36387
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
36335
36388
  * a replay needs several seconds of native pixels, not one frame.
36336
36389
  *
36337
36390
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -39695,6 +39748,7 @@ var zoneRulesCapability = {
39695
39748
  */
39696
39749
  durability: "restored"
39697
39750
  };
39751
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
39698
39752
  /**
39699
39753
  * Accessory device helpers — shared across drivers.
39700
39754
  *
@@ -40754,13 +40808,14 @@ var BaseDeviceProvider = class extends BaseAddon {
40754
40808
  async getStatus() {
40755
40809
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
40756
40810
  const summary = this.restoreFailureSummary();
40757
- if (summary === null) return {
40811
+ const base = {
40758
40812
  connected: true,
40759
- deviceCount: all.length
40813
+ deviceCount: all.length,
40814
+ motionSliceWriter: "orchestrator"
40760
40815
  };
40816
+ if (summary === null) return base;
40761
40817
  return {
40762
- connected: true,
40763
- deviceCount: all.length,
40818
+ ...base,
40764
40819
  error: summary
40765
40820
  };
40766
40821
  }
@@ -46196,6 +46251,12 @@ Object.freeze({
46196
46251
  addonId: null,
46197
46252
  access: "view"
46198
46253
  },
46254
+ "notificationRules.getAlarmSensors": {
46255
+ capName: "notification-rules",
46256
+ capScope: "system",
46257
+ addonId: null,
46258
+ access: "view"
46259
+ },
46199
46260
  "notificationRules.getClipRetentionAsks": {
46200
46261
  capName: "notification-rules",
46201
46262
  capScope: "system",
@@ -49774,6 +49835,11 @@ Object.freeze({
49774
49835
  }
49775
49836
  });
49776
49837
  Object.freeze({
49838
+ "accessories.getStatus": [{
49839
+ name: "deviceId",
49840
+ form: "single",
49841
+ optional: false
49842
+ }],
49777
49843
  "accessories.setChildHidden": [{
49778
49844
  name: "childDeviceId",
49779
49845
  form: "single",
@@ -49793,6 +49859,11 @@ Object.freeze({
49793
49859
  form: "single",
49794
49860
  optional: false
49795
49861
  }],
49862
+ "airQualitySensor.getStatus": [{
49863
+ name: "deviceId",
49864
+ form: "single",
49865
+ optional: false
49866
+ }],
49796
49867
  "alarmPanel.arm": [{
49797
49868
  name: "deviceId",
49798
49869
  form: "single",
@@ -49803,11 +49874,36 @@ Object.freeze({
49803
49874
  form: "single",
49804
49875
  optional: false
49805
49876
  }],
49877
+ "alarmPanel.getStatus": [{
49878
+ name: "deviceId",
49879
+ form: "single",
49880
+ optional: false
49881
+ }],
49806
49882
  "alarmPanel.trigger": [{
49807
49883
  name: "deviceId",
49808
49884
  form: "single",
49809
49885
  optional: false
49810
49886
  }],
49887
+ "ambientLightSensor.getStatus": [{
49888
+ name: "deviceId",
49889
+ form: "single",
49890
+ optional: false
49891
+ }],
49892
+ "audioAnalysis.applyDeviceSettingsPatch": [{
49893
+ name: "deviceId",
49894
+ form: "single",
49895
+ optional: false
49896
+ }],
49897
+ "audioAnalysis.getDeviceLiveContribution": [{
49898
+ name: "deviceId",
49899
+ form: "single",
49900
+ optional: false
49901
+ }],
49902
+ "audioAnalysis.getDeviceSettingsContribution": [{
49903
+ name: "deviceId",
49904
+ form: "single",
49905
+ optional: false
49906
+ }],
49811
49907
  "audioAnalysis.resolveDeviceSettings": [{
49812
49908
  name: "deviceId",
49813
49909
  form: "single",
@@ -49848,16 +49944,36 @@ Object.freeze({
49848
49944
  form: "single",
49849
49945
  optional: false
49850
49946
  }],
49947
+ "automationControl.getStatus": [{
49948
+ name: "deviceId",
49949
+ form: "single",
49950
+ optional: false
49951
+ }],
49851
49952
  "automationControl.trigger": [{
49852
49953
  name: "deviceId",
49853
49954
  form: "single",
49854
49955
  optional: false
49855
49956
  }],
49957
+ "battery.getStatus": [{
49958
+ name: "deviceId",
49959
+ form: "single",
49960
+ optional: false
49961
+ }],
49856
49962
  "battery.wakeForStream": [{
49857
49963
  name: "deviceId",
49858
49964
  form: "single",
49859
49965
  optional: false
49860
49966
  }],
49967
+ "binary.getStatus": [{
49968
+ name: "deviceId",
49969
+ form: "single",
49970
+ optional: false
49971
+ }],
49972
+ "brightness.getStatus": [{
49973
+ name: "deviceId",
49974
+ form: "single",
49975
+ optional: false
49976
+ }],
49861
49977
  "brightness.setBrightness": [{
49862
49978
  name: "deviceId",
49863
49979
  form: "single",
@@ -49873,6 +49989,26 @@ Object.freeze({
49873
49989
  form: "single",
49874
49990
  optional: false
49875
49991
  }],
49992
+ "cameraCredentials.getStatus": [{
49993
+ name: "deviceId",
49994
+ form: "single",
49995
+ optional: false
49996
+ }],
49997
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
49998
+ name: "deviceId",
49999
+ form: "single",
50000
+ optional: false
50001
+ }],
50002
+ "cameraGridLayout.getDeviceLiveContribution": [{
50003
+ name: "deviceId",
50004
+ form: "single",
50005
+ optional: false
50006
+ }],
50007
+ "cameraGridLayout.getDeviceSettingsContribution": [{
50008
+ name: "deviceId",
50009
+ form: "single",
50010
+ optional: false
50011
+ }],
49876
50012
  "cameraGridLayout.getLayout": [{
49877
50013
  name: "deviceId",
49878
50014
  form: "single",
@@ -49888,6 +50024,21 @@ Object.freeze({
49888
50024
  form: "single",
49889
50025
  optional: false
49890
50026
  }],
50027
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
50028
+ name: "deviceId",
50029
+ form: "single",
50030
+ optional: false
50031
+ }],
50032
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
50033
+ name: "deviceId",
50034
+ form: "single",
50035
+ optional: false
50036
+ }],
50037
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
50038
+ name: "deviceId",
50039
+ form: "single",
50040
+ optional: false
50041
+ }],
49891
50042
  "cameraStreams.getBrokerStreams": [{
49892
50043
  name: "deviceId",
49893
50044
  form: "single",
@@ -49913,6 +50064,16 @@ Object.freeze({
49913
50064
  form: "single",
49914
50065
  optional: false
49915
50066
  }],
50067
+ "carbonMonoxide.getStatus": [{
50068
+ name: "deviceId",
50069
+ form: "single",
50070
+ optional: false
50071
+ }],
50072
+ "climateControl.getStatus": [{
50073
+ name: "deviceId",
50074
+ form: "single",
50075
+ optional: false
50076
+ }],
49916
50077
  "climateControl.setFanMode": [{
49917
50078
  name: "deviceId",
49918
50079
  form: "single",
@@ -49953,16 +50114,41 @@ Object.freeze({
49953
50114
  form: "single",
49954
50115
  optional: false
49955
50116
  }],
50117
+ "color.getStatus": [{
50118
+ name: "deviceId",
50119
+ form: "single",
50120
+ optional: false
50121
+ }],
49956
50122
  "color.setColor": [{
49957
50123
  name: "deviceId",
49958
50124
  form: "single",
49959
50125
  optional: false
49960
50126
  }],
50127
+ "connectivity.getStatus": [{
50128
+ name: "deviceId",
50129
+ form: "single",
50130
+ optional: false
50131
+ }],
50132
+ "consumables.getStatus": [{
50133
+ name: "deviceId",
50134
+ form: "single",
50135
+ optional: false
50136
+ }],
49961
50137
  "consumables.reset": [{
49962
50138
  name: "deviceId",
49963
50139
  form: "single",
49964
50140
  optional: false
49965
50141
  }],
50142
+ "contact.getStatus": [{
50143
+ name: "deviceId",
50144
+ form: "single",
50145
+ optional: false
50146
+ }],
50147
+ "control.getStatus": [{
50148
+ name: "deviceId",
50149
+ form: "single",
50150
+ optional: false
50151
+ }],
49966
50152
  "control.setValue": [{
49967
50153
  name: "deviceId",
49968
50154
  form: "single",
@@ -49973,6 +50159,11 @@ Object.freeze({
49973
50159
  form: "single",
49974
50160
  optional: false
49975
50161
  }],
50162
+ "cover.getStatus": [{
50163
+ name: "deviceId",
50164
+ form: "single",
50165
+ optional: false
50166
+ }],
49976
50167
  "cover.open": [{
49977
50168
  name: "deviceId",
49978
50169
  form: "single",
@@ -49998,6 +50189,11 @@ Object.freeze({
49998
50189
  form: "single",
49999
50190
  optional: false
50000
50191
  }],
50192
+ "dayNight.getStatus": [{
50193
+ name: "deviceId",
50194
+ form: "single",
50195
+ optional: false
50196
+ }],
50001
50197
  "dayNight.setSettings": [{
50002
50198
  name: "deviceId",
50003
50199
  form: "single",
@@ -50008,11 +50204,31 @@ Object.freeze({
50008
50204
  form: "single",
50009
50205
  optional: true
50010
50206
  }],
50207
+ "detectionPipeline.applyDeviceSettingsPatch": [{
50208
+ name: "deviceId",
50209
+ form: "single",
50210
+ optional: false
50211
+ }],
50212
+ "detectionPipeline.getDeviceLiveContribution": [{
50213
+ name: "deviceId",
50214
+ form: "single",
50215
+ optional: false
50216
+ }],
50217
+ "detectionPipeline.getDeviceSettingsContribution": [{
50218
+ name: "deviceId",
50219
+ form: "single",
50220
+ optional: false
50221
+ }],
50011
50222
  "deviceAdminLink.getAdminLink": [{
50012
50223
  name: "deviceId",
50013
50224
  form: "single",
50014
50225
  optional: false
50015
50226
  }],
50227
+ "deviceAdoption.getStatus": [{
50228
+ name: "deviceId",
50229
+ form: "single",
50230
+ optional: false
50231
+ }],
50016
50232
  "deviceAdoption.release": [{
50017
50233
  name: "camDeviceId",
50018
50234
  form: "single",
@@ -50028,6 +50244,11 @@ Object.freeze({
50028
50244
  form: "single",
50029
50245
  optional: false
50030
50246
  }],
50247
+ "deviceDiscovery.getStatus": [{
50248
+ name: "deviceId",
50249
+ form: "single",
50250
+ optional: false
50251
+ }],
50031
50252
  "deviceDiscovery.listDiscovered": [{
50032
50253
  name: "deviceId",
50033
50254
  form: "single",
@@ -50047,6 +50268,21 @@ Object.freeze({
50047
50268
  form: "single",
50048
50269
  optional: false
50049
50270
  }],
50271
+ "deviceExport.applyDeviceSettingsPatch": [{
50272
+ name: "deviceId",
50273
+ form: "single",
50274
+ optional: false
50275
+ }],
50276
+ "deviceExport.getDeviceLiveContribution": [{
50277
+ name: "deviceId",
50278
+ form: "single",
50279
+ optional: false
50280
+ }],
50281
+ "deviceExport.getDeviceSettingsContribution": [{
50282
+ name: "deviceId",
50283
+ form: "single",
50284
+ optional: false
50285
+ }],
50050
50286
  "deviceExtension.listCandidates": [{
50051
50287
  name: "deviceId",
50052
50288
  form: "single",
@@ -50395,6 +50631,26 @@ Object.freeze({
50395
50631
  form: "single",
50396
50632
  optional: false
50397
50633
  }],
50634
+ "deviceStatus.getStatus": [{
50635
+ name: "deviceId",
50636
+ form: "single",
50637
+ optional: false
50638
+ }],
50639
+ "doorbell.getStatus": [{
50640
+ name: "deviceId",
50641
+ form: "single",
50642
+ optional: false
50643
+ }],
50644
+ "enumSensor.getStatus": [{
50645
+ name: "deviceId",
50646
+ form: "single",
50647
+ optional: false
50648
+ }],
50649
+ "eventEmitter.getStatus": [{
50650
+ name: "deviceId",
50651
+ form: "single",
50652
+ optional: false
50653
+ }],
50398
50654
  "faceGallery.getFaceByTrack": [{
50399
50655
  name: "deviceId",
50400
50656
  form: "single",
@@ -50409,6 +50665,11 @@ Object.freeze({
50409
50665
  form: "array",
50410
50666
  optional: true
50411
50667
  }],
50668
+ "fanControl.getStatus": [{
50669
+ name: "deviceId",
50670
+ form: "single",
50671
+ optional: false
50672
+ }],
50412
50673
  "fanControl.setDirection": [{
50413
50674
  name: "deviceId",
50414
50675
  form: "single",
@@ -50429,6 +50690,26 @@ Object.freeze({
50429
50690
  form: "single",
50430
50691
  optional: false
50431
50692
  }],
50693
+ "featureProbe.getStatus": [{
50694
+ name: "deviceId",
50695
+ form: "single",
50696
+ optional: false
50697
+ }],
50698
+ "flood.getStatus": [{
50699
+ name: "deviceId",
50700
+ form: "single",
50701
+ optional: false
50702
+ }],
50703
+ "gas.getStatus": [{
50704
+ name: "deviceId",
50705
+ form: "single",
50706
+ optional: false
50707
+ }],
50708
+ "humidifier.getStatus": [{
50709
+ name: "deviceId",
50710
+ form: "single",
50711
+ optional: false
50712
+ }],
50432
50713
  "humidifier.setMode": [{
50433
50714
  name: "deviceId",
50434
50715
  form: "single",
@@ -50444,11 +50725,26 @@ Object.freeze({
50444
50725
  form: "single",
50445
50726
  optional: false
50446
50727
  }],
50728
+ "humiditySensor.getStatus": [{
50729
+ name: "deviceId",
50730
+ form: "single",
50731
+ optional: false
50732
+ }],
50733
+ "image.getStatus": [{
50734
+ name: "deviceId",
50735
+ form: "single",
50736
+ optional: false
50737
+ }],
50447
50738
  "imageSettings.getOptions": [{
50448
50739
  name: "deviceId",
50449
50740
  form: "single",
50450
50741
  optional: false
50451
50742
  }],
50743
+ "imageSettings.getStatus": [{
50744
+ name: "deviceId",
50745
+ form: "single",
50746
+ optional: false
50747
+ }],
50452
50748
  "imageSettings.setSettings": [{
50453
50749
  name: "deviceId",
50454
50750
  form: "single",
@@ -50459,6 +50755,11 @@ Object.freeze({
50459
50755
  form: "single",
50460
50756
  optional: false
50461
50757
  }],
50758
+ "intercom.getStatus": [{
50759
+ name: "deviceId",
50760
+ form: "single",
50761
+ optional: false
50762
+ }],
50462
50763
  "intercom.handleAnswer": [{
50463
50764
  name: "deviceId",
50464
50765
  form: "single",
@@ -50489,6 +50790,11 @@ Object.freeze({
50489
50790
  form: "single",
50490
50791
  optional: false
50491
50792
  }],
50793
+ "lawnMowerControl.getStatus": [{
50794
+ name: "deviceId",
50795
+ form: "single",
50796
+ optional: false
50797
+ }],
50492
50798
  "lawnMowerControl.pause": [{
50493
50799
  name: "deviceId",
50494
50800
  form: "single",
@@ -50499,6 +50805,11 @@ Object.freeze({
50499
50805
  form: "single",
50500
50806
  optional: false
50501
50807
  }],
50808
+ "lockControl.getStatus": [{
50809
+ name: "deviceId",
50810
+ form: "single",
50811
+ optional: false
50812
+ }],
50502
50813
  "lockControl.lock": [{
50503
50814
  name: "deviceId",
50504
50815
  form: "single",
@@ -50514,6 +50825,11 @@ Object.freeze({
50514
50825
  form: "single",
50515
50826
  optional: false
50516
50827
  }],
50828
+ "mediaPlayer.getStatus": [{
50829
+ name: "deviceId",
50830
+ form: "single",
50831
+ optional: false
50832
+ }],
50517
50833
  "mediaPlayer.next": [{
50518
50834
  name: "deviceId",
50519
50835
  form: "single",
@@ -50574,6 +50890,11 @@ Object.freeze({
50574
50890
  form: "single",
50575
50891
  optional: false
50576
50892
  }],
50893
+ "motion.getStatus": [{
50894
+ name: "deviceId",
50895
+ form: "single",
50896
+ optional: false
50897
+ }],
50577
50898
  "motion.isDetected": [{
50578
50899
  name: "deviceId",
50579
50900
  form: "single",
@@ -50584,11 +50905,31 @@ Object.freeze({
50584
50905
  form: "single",
50585
50906
  optional: false
50586
50907
  }],
50908
+ "motionDetection.applyDeviceSettingsPatch": [{
50909
+ name: "deviceId",
50910
+ form: "single",
50911
+ optional: false
50912
+ }],
50913
+ "motionDetection.getDeviceLiveContribution": [{
50914
+ name: "deviceId",
50915
+ form: "single",
50916
+ optional: false
50917
+ }],
50918
+ "motionDetection.getDeviceSettingsContribution": [{
50919
+ name: "deviceId",
50920
+ form: "single",
50921
+ optional: false
50922
+ }],
50587
50923
  "motionDetection.removeCamera": [{
50588
50924
  name: "deviceId",
50589
50925
  form: "single",
50590
50926
  optional: false
50591
50927
  }],
50928
+ "motionTrigger.getStatus": [{
50929
+ name: "deviceId",
50930
+ form: "single",
50931
+ optional: false
50932
+ }],
50592
50933
  "motionTrigger.setMotionTrigger": [{
50593
50934
  name: "deviceId",
50594
50935
  form: "single",
@@ -50599,6 +50940,11 @@ Object.freeze({
50599
50940
  form: "single",
50600
50941
  optional: false
50601
50942
  }],
50943
+ "motionZones.getStatus": [{
50944
+ name: "deviceId",
50945
+ form: "single",
50946
+ optional: false
50947
+ }],
50602
50948
  "motionZones.setZone": [{
50603
50949
  name: "deviceId",
50604
50950
  form: "single",
@@ -50609,6 +50955,11 @@ Object.freeze({
50609
50955
  form: "single",
50610
50956
  optional: false
50611
50957
  }],
50958
+ "nativeObjectDetection.getStatus": [{
50959
+ name: "deviceId",
50960
+ form: "single",
50961
+ optional: false
50962
+ }],
50612
50963
  "nativeObjectDetection.setEnabled": [{
50613
50964
  name: "deviceId",
50614
50965
  form: "single",
@@ -50624,6 +50975,11 @@ Object.freeze({
50624
50975
  form: "single",
50625
50976
  optional: false
50626
50977
  }],
50978
+ "navigation.getStatus": [{
50979
+ name: "deviceId",
50980
+ form: "single",
50981
+ optional: false
50982
+ }],
50627
50983
  "navigation.goToPoint": [{
50628
50984
  name: "deviceId",
50629
50985
  form: "single",
@@ -50669,6 +51025,11 @@ Object.freeze({
50669
51025
  form: "single",
50670
51026
  optional: false
50671
51027
  }],
51028
+ "networkLink.getStatus": [{
51029
+ name: "deviceId",
51030
+ form: "single",
51031
+ optional: false
51032
+ }],
50672
51033
  "networkQuality.getDeviceStats": [{
50673
51034
  name: "deviceId",
50674
51035
  form: "single",
@@ -50679,6 +51040,11 @@ Object.freeze({
50679
51040
  form: "single",
50680
51041
  optional: false
50681
51042
  }],
51043
+ "notificationRules.getAlarmSensors": [{
51044
+ name: "deviceIds",
51045
+ form: "array",
51046
+ optional: false
51047
+ }],
50682
51048
  "notificationRules.setDeviceMuted": [{
50683
51049
  name: "deviceId",
50684
51050
  form: "single",
@@ -50689,11 +51055,26 @@ Object.freeze({
50689
51055
  form: "single",
50690
51056
  optional: false
50691
51057
  }],
51058
+ "notifier.getStatus": [{
51059
+ name: "deviceId",
51060
+ form: "single",
51061
+ optional: false
51062
+ }],
50692
51063
  "notifier.send": [{
50693
51064
  name: "deviceId",
50694
51065
  form: "single",
50695
51066
  optional: false
50696
51067
  }],
51068
+ "numericSensor.getStatus": [{
51069
+ name: "deviceId",
51070
+ form: "single",
51071
+ optional: false
51072
+ }],
51073
+ "osd.getStatus": [{
51074
+ name: "deviceId",
51075
+ form: "single",
51076
+ optional: false
51077
+ }],
50697
51078
  "osd.setOverlay": [{
50698
51079
  name: "deviceId",
50699
51080
  form: "single",
@@ -50753,6 +51134,11 @@ Object.freeze({
50753
51134
  form: "single",
50754
51135
  optional: false
50755
51136
  }],
51137
+ "petFeeder.getStatus": [{
51138
+ name: "deviceId",
51139
+ form: "single",
51140
+ optional: false
51141
+ }],
50756
51142
  "petFeeder.markFoodReplenished": [{
50757
51143
  name: "deviceId",
50758
51144
  form: "single",
@@ -50788,6 +51174,11 @@ Object.freeze({
50788
51174
  form: "single",
50789
51175
  optional: false
50790
51176
  }],
51177
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
51178
+ name: "deviceId",
51179
+ form: "single",
51180
+ optional: false
51181
+ }],
50791
51182
  "pipelineAnalytics.clearTrackRelation": [{
50792
51183
  name: "deviceId",
50793
51184
  form: "single",
@@ -50828,6 +51219,16 @@ Object.freeze({
50828
51219
  form: "single",
50829
51220
  optional: false
50830
51221
  }],
51222
+ "pipelineAnalytics.getDeviceLiveContribution": [{
51223
+ name: "deviceId",
51224
+ form: "single",
51225
+ optional: false
51226
+ }],
51227
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
51228
+ name: "deviceId",
51229
+ form: "single",
51230
+ optional: false
51231
+ }],
50831
51232
  "pipelineAnalytics.getEventDensity": [{
50832
51233
  name: "deviceId",
50833
51234
  form: "single",
@@ -51043,6 +51444,11 @@ Object.freeze({
51043
51444
  form: "single",
51044
51445
  optional: true
51045
51446
  }],
51447
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
51448
+ name: "deviceId",
51449
+ form: "single",
51450
+ optional: false
51451
+ }],
51046
51452
  "pipelineOrchestrator.assignAudio": [{
51047
51453
  name: "deviceId",
51048
51454
  form: "single",
@@ -51088,6 +51494,16 @@ Object.freeze({
51088
51494
  form: "single",
51089
51495
  optional: false
51090
51496
  }],
51497
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
51498
+ name: "deviceId",
51499
+ form: "single",
51500
+ optional: false
51501
+ }],
51502
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
51503
+ name: "deviceId",
51504
+ form: "single",
51505
+ optional: false
51506
+ }],
51091
51507
  "pipelineOrchestrator.getPipelineAssignment": [{
51092
51508
  name: "deviceId",
51093
51509
  form: "single",
@@ -51208,11 +51624,31 @@ Object.freeze({
51208
51624
  form: "single",
51209
51625
  optional: true
51210
51626
  }],
51627
+ "powerMeter.getStatus": [{
51628
+ name: "deviceId",
51629
+ form: "single",
51630
+ optional: false
51631
+ }],
51632
+ "presence.getStatus": [{
51633
+ name: "deviceId",
51634
+ form: "single",
51635
+ optional: false
51636
+ }],
51637
+ "pressureSensor.getStatus": [{
51638
+ name: "deviceId",
51639
+ form: "single",
51640
+ optional: false
51641
+ }],
51211
51642
  "privacyMask.getOptions": [{
51212
51643
  name: "deviceId",
51213
51644
  form: "single",
51214
51645
  optional: false
51215
51646
  }],
51647
+ "privacyMask.getStatus": [{
51648
+ name: "deviceId",
51649
+ form: "single",
51650
+ optional: false
51651
+ }],
51216
51652
  "privacyMask.setAudioEnabled": [{
51217
51653
  name: "deviceId",
51218
51654
  form: "single",
@@ -51263,6 +51699,11 @@ Object.freeze({
51263
51699
  form: "single",
51264
51700
  optional: false
51265
51701
  }],
51702
+ "ptz.getStatus": [{
51703
+ name: "deviceId",
51704
+ form: "single",
51705
+ optional: false
51706
+ }],
51266
51707
  "ptz.goHome": [{
51267
51708
  name: "deviceId",
51268
51709
  form: "single",
@@ -51353,6 +51794,11 @@ Object.freeze({
51353
51794
  form: "single",
51354
51795
  optional: false
51355
51796
  }],
51797
+ "recordingArchive.applyDeviceSettingsPatch": [{
51798
+ name: "deviceId",
51799
+ form: "single",
51800
+ optional: false
51801
+ }],
51356
51802
  "recordingArchive.deleteFootprint": [{
51357
51803
  name: "deviceId",
51358
51804
  form: "single",
@@ -51373,6 +51819,21 @@ Object.freeze({
51373
51819
  form: "single",
51374
51820
  optional: false
51375
51821
  }],
51822
+ "recordingArchive.getDeviceLiveContribution": [{
51823
+ name: "deviceId",
51824
+ form: "single",
51825
+ optional: false
51826
+ }],
51827
+ "recordingArchive.getDeviceSettingsContribution": [{
51828
+ name: "deviceId",
51829
+ form: "single",
51830
+ optional: false
51831
+ }],
51832
+ "recordingArchive.getStatus": [{
51833
+ name: "deviceId",
51834
+ form: "single",
51835
+ optional: false
51836
+ }],
51376
51837
  "recordingArchive.listOpsLog": [{
51377
51838
  name: "deviceId",
51378
51839
  form: "single",
@@ -51458,6 +51919,11 @@ Object.freeze({
51458
51919
  form: "single",
51459
51920
  optional: false
51460
51921
  }],
51922
+ "recordingOnboard.getStatus": [{
51923
+ name: "deviceId",
51924
+ form: "single",
51925
+ optional: false
51926
+ }],
51461
51927
  "recordingOnboard.setSettings": [{
51462
51928
  name: "deviceId",
51463
51929
  form: "single",
@@ -51488,6 +51954,11 @@ Object.freeze({
51488
51954
  form: "single",
51489
51955
  optional: false
51490
51956
  }],
51957
+ "sceneMonitor.getStatus": [{
51958
+ name: "deviceId",
51959
+ form: "single",
51960
+ optional: false
51961
+ }],
51491
51962
  "sceneMonitor.listScenes": [{
51492
51963
  name: "deviceId",
51493
51964
  form: "single",
@@ -51513,6 +51984,11 @@ Object.freeze({
51513
51984
  form: "single",
51514
51985
  optional: false
51515
51986
  }],
51987
+ "scriptRunner.getStatus": [{
51988
+ name: "deviceId",
51989
+ form: "single",
51990
+ optional: false
51991
+ }],
51516
51992
  "scriptRunner.run": [{
51517
51993
  name: "deviceId",
51518
51994
  form: "single",
@@ -51523,11 +51999,31 @@ Object.freeze({
51523
51999
  form: "single",
51524
52000
  optional: false
51525
52001
  }],
52002
+ "smoke.getStatus": [{
52003
+ name: "deviceId",
52004
+ form: "single",
52005
+ optional: false
52006
+ }],
52007
+ "snapshot.applyDeviceSettingsPatch": [{
52008
+ name: "deviceId",
52009
+ form: "single",
52010
+ optional: false
52011
+ }],
51526
52012
  "snapshot.getDebugState": [{
51527
52013
  name: "deviceId",
51528
52014
  form: "single",
51529
52015
  optional: false
51530
52016
  }],
52017
+ "snapshot.getDeviceLiveContribution": [{
52018
+ name: "deviceId",
52019
+ form: "single",
52020
+ optional: false
52021
+ }],
52022
+ "snapshot.getDeviceSettingsContribution": [{
52023
+ name: "deviceId",
52024
+ form: "single",
52025
+ optional: false
52026
+ }],
51531
52027
  "snapshot.getSnapshot": [{
51532
52028
  name: "deviceId",
51533
52029
  form: "single",
@@ -51544,6 +52040,11 @@ Object.freeze({
51544
52040
  form: "array",
51545
52041
  optional: false
51546
52042
  }],
52043
+ "snapshot.getStatus": [{
52044
+ name: "deviceId",
52045
+ form: "single",
52046
+ optional: false
52047
+ }],
51547
52048
  "snapshot.invalidateCache": [{
51548
52049
  name: "deviceId",
51549
52050
  form: "single",
@@ -51554,6 +52055,11 @@ Object.freeze({
51554
52055
  form: "single",
51555
52056
  optional: false
51556
52057
  }],
52058
+ "streamBroker.applyDeviceSettingsPatch": [{
52059
+ name: "deviceId",
52060
+ form: "single",
52061
+ optional: false
52062
+ }],
51557
52063
  "streamBroker.assignProfile": [{
51558
52064
  name: "deviceId",
51559
52065
  form: "single",
@@ -51569,6 +52075,16 @@ Object.freeze({
51569
52075
  form: "single",
51570
52076
  optional: false
51571
52077
  }],
52078
+ "streamBroker.getDeviceLiveContribution": [{
52079
+ name: "deviceId",
52080
+ form: "single",
52081
+ optional: false
52082
+ }],
52083
+ "streamBroker.getDeviceSettingsContribution": [{
52084
+ name: "deviceId",
52085
+ form: "single",
52086
+ optional: false
52087
+ }],
51572
52088
  "streamBroker.getStreamWithCodec": [{
51573
52089
  name: "deviceId",
51574
52090
  form: "single",
@@ -51629,16 +52145,46 @@ Object.freeze({
51629
52145
  form: "single",
51630
52146
  optional: false
51631
52147
  }],
52148
+ "streamParams.getStatus": [{
52149
+ name: "deviceId",
52150
+ form: "single",
52151
+ optional: false
52152
+ }],
51632
52153
  "streamParams.setProfile": [{
51633
52154
  name: "deviceId",
51634
52155
  form: "single",
51635
52156
  optional: false
51636
52157
  }],
52158
+ "switch.getStatus": [{
52159
+ name: "deviceId",
52160
+ form: "single",
52161
+ optional: false
52162
+ }],
51637
52163
  "switch.setState": [{
51638
52164
  name: "deviceId",
51639
52165
  form: "single",
51640
52166
  optional: false
51641
52167
  }],
52168
+ "tamper.getStatus": [{
52169
+ name: "deviceId",
52170
+ form: "single",
52171
+ optional: false
52172
+ }],
52173
+ "temperatureSensor.getStatus": [{
52174
+ name: "deviceId",
52175
+ form: "single",
52176
+ optional: false
52177
+ }],
52178
+ "update.getStatus": [{
52179
+ name: "deviceId",
52180
+ form: "single",
52181
+ optional: false
52182
+ }],
52183
+ "vacuumControl.getStatus": [{
52184
+ name: "deviceId",
52185
+ form: "single",
52186
+ optional: false
52187
+ }],
51642
52188
  "vacuumControl.locate": [{
51643
52189
  name: "deviceId",
51644
52190
  form: "single",
@@ -51674,6 +52220,11 @@ Object.freeze({
51674
52220
  form: "single",
51675
52221
  optional: false
51676
52222
  }],
52223
+ "valve.getStatus": [{
52224
+ name: "deviceId",
52225
+ form: "single",
52226
+ optional: false
52227
+ }],
51677
52228
  "valve.open": [{
51678
52229
  name: "deviceId",
51679
52230
  form: "single",
@@ -51689,6 +52240,11 @@ Object.freeze({
51689
52240
  form: "single",
51690
52241
  optional: false
51691
52242
  }],
52243
+ "vibration.getStatus": [{
52244
+ name: "deviceId",
52245
+ form: "single",
52246
+ optional: false
52247
+ }],
51692
52248
  "videoclips.dialClipStream": [{
51693
52249
  name: "deviceId",
51694
52250
  form: "single",
@@ -51724,6 +52280,11 @@ Object.freeze({
51724
52280
  form: "single",
51725
52281
  optional: false
51726
52282
  }],
52283
+ "waterHeater.getStatus": [{
52284
+ name: "deviceId",
52285
+ form: "single",
52286
+ optional: false
52287
+ }],
51727
52288
  "waterHeater.setAway": [{
51728
52289
  name: "deviceId",
51729
52290
  form: "single",
@@ -51739,6 +52300,11 @@ Object.freeze({
51739
52300
  form: "single",
51740
52301
  optional: false
51741
52302
  }],
52303
+ "weather.getStatus": [{
52304
+ name: "deviceId",
52305
+ form: "single",
52306
+ optional: false
52307
+ }],
51742
52308
  "webrtcSession.addIceCandidate": [{
51743
52309
  name: "deviceId",
51744
52310
  form: "single",
@@ -52476,7 +53042,7 @@ var PreviewTextField = string().max(200);
52476
53042
  * Whether the notification's preview is a STILL or a short animation.
52477
53043
  *
52478
53044
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
52479
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
53045
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
52480
53046
  * night reads better as three seconds of motion than as one frame of it. Both
52481
53047
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
52482
53048
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -52614,6 +53180,7 @@ TimelapseRuleInputSchema.extend({
52614
53180
  createdAt: number(),
52615
53181
  updatedAt: number()
52616
53182
  });
53183
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
52617
53184
  object({
52618
53185
  /**
52619
53186
  * Fraction of the box's own size added on EACH side before cutting.