@camstack/addon-provider-gree 0.2.115 → 0.2.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +892 -325
  2. package/dist/addon.mjs +892 -325
  3. package/package.json +1 -3
package/dist/addon.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let dgram = require("dgram");
3
3
  let crypto$1 = require("crypto");
4
4
  let events = require("events");
5
- //#region ../types/dist/event-category-C5xZWqz6.mjs
5
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
6
6
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
7
7
  EventCategory["SystemBoot"] = "system.boot";
8
8
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -535,6 +535,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
535
535
  */
536
536
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
537
537
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
538
+ /**
539
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
540
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
541
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
542
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
543
+ * for a camera with no attached sensor). Providers must not emit
544
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
545
+ * keeps it so (camera-grid is a named, deferred exception).
546
+ */
538
547
  EventCategory["ProviderMotion"] = "provider.motion";
539
548
  EventCategory["ProviderDetection"] = "provider.detection";
540
549
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5373,7 +5382,7 @@ var ZodIssueCode = {
5373
5382
  var ZodFirstPartyTypeKind;
5374
5383
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5375
5384
  //#endregion
5376
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5385
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5377
5386
  /**
5378
5387
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5379
5388
  * window to float samples (D455).
@@ -7416,7 +7425,7 @@ function errMsg(err) {
7416
7425
  return String(err);
7417
7426
  }
7418
7427
  //#endregion
7419
- //#region ../types/dist/composition-Dq42XWp0.mjs
7428
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
7420
7429
  /**
7421
7430
  * The ffmpeg build every CamStack node downloads, per platform and arch.
7422
7431
  *
@@ -7470,21 +7479,20 @@ function portable(target) {
7470
7479
  }
7471
7480
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
7472
7481
  /**
7473
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7474
- * valutatore puro del suo FRONTE.
7482
+ * THE table "which boolean of this device type counts as HIGH", and the
7483
+ * pure evaluator of its EDGE.
7475
7484
  *
7476
- * Viveva dentro il builtin virtual-doorbell
7477
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7478
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7479
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7480
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7481
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7482
- * SPOSTA qui e il doorbell la ri-esporta.
7485
+ * ONE table for everyone who asks "is this device HIGH?": the
7486
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
7487
+ * sensor markers, the orchestrator's camera-sensors bridge and
7488
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
7489
+ * A second copy would diverge at the first cap added, and the symptom — "the
7490
+ * sensor rings the doorbell but does not record" — is exactly D62.
7483
7491
  *
7484
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7485
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7486
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7487
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7492
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
7493
+ * two must not be unified: that one answers "what is the state WORD for a
7494
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
7495
+ * boolean's EDGE counts". Deliberately different vocabularies.
7488
7496
  */
7489
7497
  /**
7490
7498
  * Known binary / switch source caps → the boolean slice field whose
@@ -9093,22 +9101,22 @@ var CLASS_MAP_MACRO_TARGETS = [
9093
9101
  "package"
9094
9102
  ];
9095
9103
  /**
9096
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
9097
- * un operatore può selezionare.
9104
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
9105
+ * an operator can select.
9098
9106
  *
9099
- * Sono le tre offerte dallo step `object-detection`
9107
+ * They are the three offered by the `object-detection` step
9100
9108
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
9101
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
9102
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
9103
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
9104
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
9109
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
9110
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
9111
+ * `package-detection`, whose enablement is driven by zones, and offering the
9112
+ * same word twice has already made an operator turn on the COCO proxy
9105
9113
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
9106
9114
  *
9107
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
9108
- * dello step e una seconda volta come union `FirstLevelMacro`
9109
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
9110
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
9111
- * successiva.
9115
+ * ONE list. Before today the same three were hand-written in the step's offer
9116
+ * and a second time as the union `FirstLevelMacro`
9117
+ * (`types/detection.ts`); a third copy for the recording trigger
9118
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
9119
+ * invisible.
9112
9120
  */
9113
9121
  var FIRST_LEVEL_MACRO_CLASSES = [
9114
9122
  "person",
@@ -9173,17 +9181,17 @@ var RecordingStorageModeSchema = _enum([
9173
9181
  "on-device-decision"
9174
9182
  ]);
9175
9183
  /**
9176
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
9177
- * tre offerte dallo step `object-detection`, da UNA lista
9184
+ * The macro classes that can open a recording window — the same
9185
+ * three offered by the `object-detection` step, from ONE list
9178
9186
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
9179
9187
  */
9180
9188
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
9181
9189
  /**
9182
- * True quando `values` non ripete un elemento.
9190
+ * True when `values` does not repeat an element.
9183
9191
  *
9184
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
9185
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
9186
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
9192
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
9193
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
9194
+ * would count its windows twice in `segmentMissedByMs`.
9187
9195
  */
9188
9196
  var noDuplicates = (values) => new Set(values).size === values.length;
9189
9197
  /** Which detectors trigger an `events`-mode band. */
@@ -9191,34 +9199,34 @@ var RecordingTriggersSchema = object({
9191
9199
  motion: boolean().optional(),
9192
9200
  audioThresholdDbfs: number().optional(),
9193
9201
  /**
9194
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
9195
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
9196
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
9197
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
9202
+ * The macro classes whose detection opens a window. ABSENT = the source
9203
+ * is not listened to; an EMPTY array is rejected, because "events band, object
9204
+ * trigger on, no class" is the same shape "enabled and records
9205
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
9198
9206
  *
9199
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
9200
- * quelle che hanno attraversato `enabledMacroClasses`, i
9201
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
9202
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
9203
- * finestre — vedi `recorder/object-trigger.ts`.
9207
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
9208
+ * those that went through `enabledMacroClasses`, the
9209
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
9210
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
9211
+ * windows — see `recorder/object-trigger.ts`.
9204
9212
  */
9205
9213
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
9206
9214
  /**
9207
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
9208
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
9215
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
9216
+ * is not listened to; an empty array is rejected for the same reason as
9209
9217
  * `objectClasses`.
9210
9218
  *
9211
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
9212
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
9213
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
9214
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9215
- * device (D12) — mai un elenco globale di cap.
9219
+ * These are SOURCE device ids, not cameras: the band names them, so the
9220
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
9221
+ * does no RPC. The OFFER from which the operator picks them is another question, and
9222
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9223
+ * device (D12) — never a global list of caps.
9216
9224
  *
9217
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9218
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9219
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9220
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
9221
- * registrare.
9225
+ * What "high" means depends on the device TYPE and is not decided here:
9226
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
9227
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
9228
+ * the level: a contact found already open at runner restart does not
9229
+ * record.
9222
9230
  */
9223
9231
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9224
9232
  });
@@ -10295,7 +10303,7 @@ var DecoderSessionConfigSchema = object({
10295
10303
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
10296
10304
  * thing: the logging settings document on the `system` cap. Two authorities
10297
10305
  * over the values is the exact defect
10298
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
10306
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
10299
10307
  * remove; re-introducing it from the cure side would be grotesque.
10300
10308
  *
10301
10309
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -12006,7 +12014,7 @@ var BrokerStatusEnum = _enum([
12006
12014
  "unreachable",
12007
12015
  "error"
12008
12016
  ]);
12009
- var BrokerInfoSchema$1 = object({
12017
+ var BrokerInfoSchema = object({
12010
12018
  /** Stable broker id. Persisted; survives addon restarts. */
12011
12019
  id: string(),
12012
12020
  /** Addon id of the provider that OWNS this broker.
@@ -12139,7 +12147,7 @@ var GetStateInputSchema = object({
12139
12147
  * HA: entity_id (returns the cached entity state). */
12140
12148
  key: string()
12141
12149
  });
12142
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12150
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12143
12151
  kind: "mutation",
12144
12152
  auth: "admin"
12145
12153
  }), method(RemoveInputSchema, _void(), {
@@ -13850,7 +13858,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
13850
13858
  *
13851
13859
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
13852
13860
  * was wrong — corrected 2026-08-26 after the hop map
13853
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
13861
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
13854
13862
  * There is **no Zod parse at all** between the door and the engine: the
13855
13863
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
13856
13864
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -14713,7 +14721,17 @@ var SiteZoneSchema = object({
14713
14721
  var ProviderStatusSchema = object({
14714
14722
  connected: boolean(),
14715
14723
  deviceCount: number(),
14716
- error: string().optional()
14724
+ error: string().optional(),
14725
+ /**
14726
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14727
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14728
+ * which every provider bundles, so only a provider BUILT from D696-amended
14729
+ * code says it. ABSENT means an older provider that may still write it (raw
14730
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14731
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14732
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14733
+ */
14734
+ motionSliceWriter: literal("orchestrator").optional()
14717
14735
  });
14718
14736
  object({
14719
14737
  externalId: string(),
@@ -15592,109 +15610,10 @@ method(object({
15592
15610
  deviceIds: array(number()).readonly(),
15593
15611
  caps: array(string()).readonly().optional()
15594
15612
  }), record(string(), record(string(), unknown().nullable())));
15595
- /**
15596
- * Doorbell button cap. Two kinds of providers coexist behind this cap
15597
- * name (same pattern as `snapshot`):
15598
- *
15599
- * - **Native** providers: registered per-device by device-driver
15600
- * addons via `ctx.registerNativeCap` — either on a
15601
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
15602
- * or directly on the camera (Reolink registers at camera level).
15603
- * Emits an `onPressed` event every time the firmware pushes a
15604
- * ring; status tracks the last press and a pressCount since start
15605
- * (diagnostic).
15606
- *
15607
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
15608
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
15609
- * device (contact / switch / event-emitter …) into a doorbell for
15610
- * a camera. `defaultActive: false` — the operator explicitly binds
15611
- * it per camera in the device-bindings UI, then picks the source
15612
- * device + trigger in the per-device settings.
15613
- *
15614
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
15615
- * — subscribers listening at the camera level receive ring events
15616
- * with `via[]` populated. No code on the parent needed.
15617
- */
15618
- var DoorbellStatusSchema = object({
15619
- /** Ms epoch of the last press. null = never observed since this provider started. */
15620
- lastPressedAt: number().nullable(),
15621
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15622
- pressCountSinceStart: number()
15623
- });
15624
- var DoorbellPressEventSchema = object({
15625
- deviceId: number(),
15626
- timestamp: number()
15627
- });
15628
- /**
15629
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15630
- * virtual-doorbell trigger devices, exactly what the wrapper's
15631
- * `doorbellSources` persists (as `{ deviceId }` records).
15632
- */
15633
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15634
- /**
15635
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
15636
- * doorbell, owned by the `virtual-doorbell` wrapper over its
15637
- * `doorbellSources` store (D648). A source rings when one of its
15638
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
15639
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
15640
- * reports it, it never writes it.
15641
- */
15642
- var DOORBELL_SOURCE_SLOT = {
15643
- id: "doorbell-source",
15644
- label: "Doorbell trigger devices",
15645
- 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.",
15646
- shape: "association",
15647
- hostDeviceTypes: [DeviceType.Camera],
15648
- sourceCaps: SOURCE_CAPS,
15649
- cardinality: "many",
15650
- value: DoorbellSourceSlotValueSchema
15651
- };
15652
- var doorbellCapability = {
15653
- name: "doorbell",
15654
- scope: "device",
15655
- deviceNative: true,
15656
- mode: "singleton",
15657
- kind: "wrapper",
15658
- defaultActive: false,
15659
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
15660
- extensionSlots: [DOORBELL_SOURCE_SLOT],
15661
- methods: {},
15662
- events: {
15663
- /**
15664
- * Fires once per physical press. Reolink delivers via Baichuan
15665
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
15666
- * release/duration — it's a pulse.
15667
- */
15668
- onPressed: {
15669
- data: DoorbellPressEventSchema,
15670
- fromState: {
15671
- field: "lastPressedAt",
15672
- on: "advance"
15673
- }
15674
- } },
15675
- status: {
15676
- schema: DoorbellStatusSchema,
15677
- kind: "push"
15678
- },
15679
- /**
15680
- * Runtime-state slice — last press timestamp + lifetime press count.
15681
- * Mirrored by the kernel and readable via
15682
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
15683
- * without subscribing.
15684
- */
15685
- runtimeState: DoorbellStatusSchema,
15686
- /**
15687
- * 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.
15688
- *
15689
- * See `RuntimeStateDurability`. Enforced by
15690
- * `scripts/check-runtime-state-durability.ts`.
15691
- */
15692
- durability: "restored"
15693
- };
15694
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15695
- DeviceType.Camera, DeviceType.Camera;
15613
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15614
+ DeviceType.Camera;
15696
15615
  /** A slot's editable value, discriminated on `slot`. */
15697
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15616
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15698
15617
  DeviceType.Camera;
15699
15618
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15700
15619
  state: literal("unreachable"),
@@ -15731,10 +15650,11 @@ var ExtensionSlotSourceSchema = object({
15731
15650
  });
15732
15651
  /**
15733
15652
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15734
- * reported read-only, named, never written through this contract (D62). The
15735
- * virtual doorbell's sources ring only while the wrapper is bound to the
15736
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15737
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15653
+ * reported read-only, named, never written through this contract (D62) — e.g.
15654
+ * a slot whose sources act only while a wrapper is bound to the host, a
15655
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15656
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15657
+ * not be read; it is not "inactive" (D315).
15738
15658
  */
15739
15659
  var ExtensionSlotActivationSchema = object({
15740
15660
  state: _enum([
@@ -15750,7 +15670,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15750
15670
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15751
15671
  slotRef: string(),
15752
15672
  slot: ExtensionSlotIdSchema,
15753
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15673
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15754
15674
  authority: string(),
15755
15675
  activation: ExtensionSlotActivationSchema.nullable(),
15756
15676
  value: ExtensionSlotValueSchema,
@@ -16028,7 +15948,7 @@ method(object({
16028
15948
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16029
15949
  * ends in a log line, and a log line is the thing the operator asked to stop
16030
15950
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16031
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
15951
+ * 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
16032
15952
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16033
15953
  * media blackout were both diagnosed. The counters stay; this is where they can
16034
15954
  * be READ.
@@ -17404,7 +17324,7 @@ var BrokerStatusSchema$1 = _enum([
17404
17324
  "unreachable",
17405
17325
  "tls-error"
17406
17326
  ]);
17407
- var BrokerInfoSchema = object({
17327
+ var BrokerInfoSchema$1 = object({
17408
17328
  id: string(),
17409
17329
  name: string(),
17410
17330
  url: string(),
@@ -17467,7 +17387,7 @@ var StatusSchema = object({
17467
17387
  brokerCount: number(),
17468
17388
  embeddedRunning: boolean()
17469
17389
  });
17470
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17390
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17471
17391
  kind: "mutation",
17472
17392
  auth: "admin"
17473
17393
  }), method(IdInputSchema, _void(), {
@@ -19681,78 +19601,16 @@ var NcRuleInputSchema = object({
19681
19601
  */
19682
19602
  confirm: NcConfirmSchema.optional(),
19683
19603
  /**
19684
- * WAIT for face/plate recognition before saying anything.
19685
- *
19686
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
19687
- * send; the identity is neither. A face is confirmed after `confirmFrames`
19688
- * agreeing observations — p50 **11.4 s** after the track was first seen,
19689
- * measured on this hub — and an `immediate` rule enqueues on the first object
19690
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
19691
- * immediate path, and no amount of media re-resolution fixes a sentence.
19692
- *
19693
- * Only two honest answers exist, and this flag picks between them. It has
19694
- * effect ONLY on a rule that declares a recognition scope
19695
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
19696
- * other rule there is nothing to wait for and the flag is inert.
19697
- *
19698
- * | value | what happens |
19699
- * | --- | --- |
19700
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
19701
- * | 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) |
19702
- *
19703
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19704
- * on the addon cap path, and absent has to keep meaning exactly what every
19705
- * rule authored before this field meant.
19706
- *
19707
- * The cost of `true` is stated here because the editor states it too: a rule
19708
- * that waits also inherits track-close SEMANTICS — its `zones` condition
19709
- * tests every zone the track visited and a `crossing` condition can no longer
19710
- * be satisfied, because a closed track carries no crossing.
19604
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
19605
+ * seconds; the rule sends ONE message when the window closes — early, once every
19606
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
19607
+ * the rule matched, with one mosaic tile per subject.
19608
+ * Absent = plain immediate (one message per track, at the first match).
19609
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
19610
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
19611
+ * path does not run Zod defaults.
19711
19612
  */
19712
- waitForEnhancement: boolean().optional(),
19713
- /**
19714
- * GROUP a burst of subjects into ONE notification that grows.
19715
- *
19716
- * Seconds of quiet after the last matching subject before the burst is
19717
- * considered over. While it is open, the first subject enqueues immediately —
19718
- * **exactly as today, with no added latency** — and every real growth (a new
19719
- * subject, or a name confirmed on one already in it) REPLACES that
19720
- * notification with an updated one naming everybody. The push carries the
19721
- * group's own coalescing tag, so the phone replaces rather than stacks.
19722
- *
19723
- * `0` / absent = off, and off is today's behaviour byte for byte.
19724
- *
19725
- * ### Why an idle cutoff and not a window
19726
- *
19727
- * The measured seven-person arrival on device 590 spans 110 s with every
19728
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
19729
- * idle cutoff holds it as one and ends it when the arrival actually ends.
19730
- * 30 s is a widely shipped value for the same decision.
19731
- *
19732
- * ### What it replaces
19733
- *
19734
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
19735
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
19736
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
19737
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
19738
- * A group collapses the same volume by MERGING, so the cooldown becomes a
19739
- * budget over GROUPS — which is what it always meant — and a growth is never
19740
- * throttled by the window its own first member spent.
19741
- *
19742
- * ### Interaction with {@link waitForEnhancement}
19743
- *
19744
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
19745
- * TRACK CLOSE, so with both set the group is opened by the first member to
19746
- * CLOSE — already carrying its name — and grows as later members close. That
19747
- * is later, and complete. With grouping alone the group opens on the first
19748
- * object event and picks up names as they are confirmed, through the growth
19749
- * path. Neither combination fires twice for one subject.
19750
- *
19751
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19752
- * on the addon cap path, so absent must keep meaning what it meant before this
19753
- * field existed.
19754
- */
19755
- groupIdleSec: number().int().min(0).max(600).optional()
19613
+ groupingSec: number().int().min(5).max(60).optional()
19756
19614
  });
19757
19615
  /**
19758
19616
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -19800,9 +19658,10 @@ var NcRuleClearableKeySchema = _enum([
19800
19658
  "targetUsers",
19801
19659
  "snoozeOptions",
19802
19660
  "snoozeAllowGlobal",
19803
- "waitForEnhancement",
19804
19661
  "actions",
19805
19662
  "confirm",
19663
+ "groupingSec",
19664
+ "waitForEnhancement",
19806
19665
  "groupIdleSec"
19807
19666
  ]);
19808
19667
  var NcRuleUpdateInputSchema = object({
@@ -19824,9 +19683,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19824
19683
  */
19825
19684
  disabledTargetIds: array(string()).default([])
19826
19685
  });
19686
+ /**
19687
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19688
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
19689
+ * job is not an open state, and the alarm stays instant.
19690
+ */
19691
+ var NcStateSummarySectionIdSchema = _enum([
19692
+ "device-state",
19693
+ "streams",
19694
+ "battery",
19695
+ "consumables",
19696
+ "tanks",
19697
+ "detection-blind",
19698
+ "nodes",
19699
+ "addons",
19700
+ "updates"
19701
+ ]);
19827
19702
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
19828
19703
  var NcStateSummaryPreviewSectionSchema = object({
19829
- id: string(),
19704
+ id: NcStateSummarySectionIdSchema,
19830
19705
  status: _enum(["read", "unavailable"]),
19831
19706
  items: number().int().nonnegative(),
19832
19707
  reason: string().optional()
@@ -19836,7 +19711,7 @@ var NcStateSummaryPreviewSectionSchema = object({
19836
19711
  * a `rule` split (no `section`), one section's on a `section` split.
19837
19712
  */
19838
19713
  var NcStateSummaryPreviewRowSchema = object({
19839
- section: string().optional(),
19714
+ section: NcStateSummarySectionIdSchema.optional(),
19840
19715
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19841
19716
  title: string(),
19842
19717
  text: string(),
@@ -20273,6 +20148,29 @@ object({
20273
20148
  firstAt: number(),
20274
20149
  lastAt: number()
20275
20150
  });
20151
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20152
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20153
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20154
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20155
+ var NcAlarmModeDelaysListSchema = array(object({
20156
+ mode: AlarmArmModeSchema,
20157
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20158
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20159
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20160
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20161
+ var NcAlarmModeDelaysEditListSchema = array(object({
20162
+ mode: AlarmArmModeSchema,
20163
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20164
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20165
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20166
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20167
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20168
+ var NcAlarmNonBlockingEditSchema = object({
20169
+ mode: AlarmArmModeSchema,
20170
+ deviceId: number().int().positive(),
20171
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20172
+ nonBlocking: boolean()
20173
+ });
20276
20174
  /**
20277
20175
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20278
20176
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20281,10 +20179,10 @@ object({
20281
20179
  var NcAlarmNonBlockingListSchema = array(object({
20282
20180
  mode: AlarmArmModeSchema,
20283
20181
  deviceIds: array(number().int()).max(200)
20284
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20182
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20285
20183
  /**
20286
- * The three durations the panel's state machine runs on, who hears about its
20287
- * transitions, and which openings each mode tolerates.
20184
+ * The three durations — global, and per mode since D697 — the panel's state
20185
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20288
20186
  *
20289
20187
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20290
20188
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20294,15 +20192,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20294
20192
  */
20295
20193
  var NcAlarmSettingsSchema = object({
20296
20194
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20297
- exitDelaySec: number().int().min(0).max(600),
20195
+ exitDelaySec: NcAlarmDelaySecSchema,
20298
20196
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20299
- entryDelaySec: number().int().min(0).max(600),
20197
+ entryDelaySec: NcAlarmDelaySecSchema,
20300
20198
  /**
20301
20199
  * How long `triggered` lasts before the panel re-arms itself.
20302
20200
  * **0 = until an operator disarms it** — the behaviour before this field
20303
20201
  * existed, and therefore what an untouched install keeps doing.
20304
20202
  */
20305
- triggeredDurationSec: number().int().min(0).max(3600),
20203
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20306
20204
  /**
20307
20205
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20308
20206
  * remove after one release. Optional so an older admin's patch (which still
@@ -20325,17 +20223,30 @@ var NcAlarmSettingsSchema = object({
20325
20223
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20326
20224
  * parses as "every opening blocks" — the behaviour it was written under.
20327
20225
  */
20328
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20226
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20227
+ /**
20228
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20229
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20230
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20231
+ */
20232
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20329
20233
  });
20330
20234
  /**
20331
20235
  * Every field optional — a tab edits one control at a time.
20332
20236
  *
20333
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20334
- * remove an inner `.default()`, so a patch that never named the field would
20335
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20336
- * (the same trap {@link NcRulePatchSchema} documents).
20237
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20238
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20239
+ * named the field would parse to `[]` and wipe every mode's list on an
20240
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20241
+ * `modeDelays` means EDITS, not the stored overrides.
20337
20242
  */
20338
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20243
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20244
+ nonBlocking: NcAlarmNonBlockingListSchema,
20245
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20246
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20247
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20248
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20249
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20339
20250
  /**
20340
20251
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20341
20252
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20435,6 +20346,28 @@ var NcAlarmConfigSchema = object({
20435
20346
  */
20436
20347
  live: NcAlarmLiveSchema.optional()
20437
20348
  });
20349
+ var NcAlarmSensorReadingSchema = _enum([
20350
+ "open",
20351
+ "closed",
20352
+ "unknown",
20353
+ "not-opening"
20354
+ ]);
20355
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20356
+ var NcAlarmSensorStateSchema = object({
20357
+ deviceId: number().int().positive(),
20358
+ reading: NcAlarmSensorReadingSchema,
20359
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20360
+ state: string().nullable(),
20361
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20362
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20363
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20364
+ online: boolean().nullable()
20365
+ });
20366
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20367
+ var NcAlarmSensorsSchema = object({
20368
+ sensors: array(NcAlarmSensorStateSchema),
20369
+ readAt: number().int().nonnegative()
20370
+ });
20438
20371
  /**
20439
20372
  * ONE rule's demand on ONE camera's clip ring.
20440
20373
  *
@@ -20525,7 +20458,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20525
20458
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20526
20459
  kind: "mutation",
20527
20460
  auth: "admin"
20528
- });
20461
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20529
20462
  /**
20530
20463
  * Zod schemas for persisted record types.
20531
20464
  *
@@ -20872,12 +20805,26 @@ var CameraSensorRefSchema = object({
20872
20805
  function cameraSensorRefKey(ref) {
20873
20806
  return `${ref.addonId}/${ref.stableId}`;
20874
20807
  }
20875
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20876
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20877
- var CameraSensorsConfigSchema = object({
20878
- mode: CameraSensorsModeSchema,
20879
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20880
- }).superRefine((value, ctx) => {
20808
+ /**
20809
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20810
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20811
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20812
+ * camera's own motion counts only while a confirm sensor is active — with or
20813
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20814
+ */
20815
+ var CameraSensorModeSchema = _enum([
20816
+ "in-addition",
20817
+ "confirm",
20818
+ "replace"
20819
+ ]);
20820
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20821
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20822
+ /**
20823
+ * A camera's attached sensors. A CS-1 row carried an envelope
20824
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20825
+ * what the write stores (D672 rule 3), so it is never written again.
20826
+ */
20827
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20881
20828
  const seen = /* @__PURE__ */ new Set();
20882
20829
  value.sensors.forEach((ref, index) => {
20883
20830
  const key = cameraSensorRefKey(ref);
@@ -20889,39 +20836,41 @@ var CameraSensorsConfigSchema = object({
20889
20836
  seen.add(key);
20890
20837
  });
20891
20838
  });
20892
- var RefFields = {
20839
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20840
+ var AttachmentFields = {
20893
20841
  addonId: string(),
20894
- stableId: string()
20842
+ stableId: string(),
20843
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20895
20844
  };
20896
20845
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20897
20846
  object({
20898
- ...RefFields,
20847
+ ...AttachmentFields,
20899
20848
  state: literal("ready"),
20900
20849
  deviceId: number(),
20901
20850
  name: string(),
20902
20851
  caps: array(string()).readonly()
20903
20852
  }),
20904
20853
  object({
20905
- ...RefFields,
20854
+ ...AttachmentFields,
20906
20855
  state: literal("offline"),
20907
20856
  deviceId: number(),
20908
20857
  name: string(),
20909
20858
  reason: _enum(["offline", "disabled"])
20910
20859
  }),
20911
20860
  object({
20912
- ...RefFields,
20861
+ ...AttachmentFields,
20913
20862
  state: literal("missing"),
20914
20863
  reason: string()
20915
20864
  }),
20916
20865
  object({
20917
- ...RefFields,
20866
+ ...AttachmentFields,
20918
20867
  state: literal("unsupported"),
20919
20868
  deviceId: number(),
20920
20869
  name: string(),
20921
20870
  reason: string()
20922
20871
  }),
20923
20872
  object({
20924
- ...RefFields,
20873
+ ...AttachmentFields,
20925
20874
  state: literal("unreadable"),
20926
20875
  reason: string()
20927
20876
  })
@@ -20934,17 +20883,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20934
20883
  * say.
20935
20884
  */
20936
20885
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20886
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20887
+ var CameraOwnMotionSchema = _enum([
20888
+ "always",
20889
+ "when-confirmed",
20890
+ "never"
20891
+ ]);
20892
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20893
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20894
+ /**
20895
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20896
+ * never the effective value. The camera's `motion` slice is the effective one,
20897
+ * so a view of the camera's own row reads this.
20898
+ * - `atMs`: when the bridge received the camera's last own edge.
20899
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20900
+ * AND it is younger than the window the bridge counts the camera's own motion
20901
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20902
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20903
+ * within the window; a status read is a snapshot, so a live view re-asks.
20904
+ * Absent = this orchestrator has not received the camera's own motion since it
20905
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20906
+ */
20907
+ var CameraRawLevelSchema = object({
20908
+ detected: boolean(),
20909
+ atMs: number()
20910
+ });
20937
20911
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
20938
- object({ state: literal("not-configured") }),
20912
+ object({
20913
+ state: literal("not-configured"),
20914
+ cameraLevel: CameraRawLevelSchema.optional()
20915
+ }),
20939
20916
  object({
20940
20917
  state: literal("unreadable"),
20941
- reason: string()
20918
+ reason: string(),
20919
+ cameraLevel: CameraRawLevelSchema.optional()
20942
20920
  }),
20943
20921
  object({
20944
20922
  state: literal("configured"),
20945
- mode: CameraSensorsModeSchema,
20923
+ cameraLevel: CameraRawLevelSchema.optional(),
20946
20924
  sensors: array(CameraSensorAttachmentSchema).readonly(),
20947
- notForwarded: CameraSensorsNotForwardedSchema.optional()
20925
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
20926
+ cameraMotion: CameraOwnMotionSchema.optional(),
20927
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
20928
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
20948
20929
  })
20949
20930
  ]);
20950
20931
  Object.freeze({
@@ -21629,14 +21610,14 @@ var TrackSchema = object({
21629
21610
  * `derive-returned-null tile=standin`,
21630
21611
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
21631
21612
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
21632
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
21613
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
21633
21614
  * tile is a face/plate stand-in, a raster crop, or an icon.
21634
21615
  *
21635
21616
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
21636
21617
  * the TILE ranked below native, so a track whose thumbnail landed natively
21637
21618
  * while its key frame missed carried no reason at all — three of the four
21638
21619
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
21639
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
21620
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
21640
21621
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
21641
21622
  * lastFrame copy source`), so its absence is now on this line whatever the
21642
21623
  * tile ended up being.
@@ -21723,7 +21704,7 @@ var MotionEventSchema = object({
21723
21704
  /**
21724
21705
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
21725
21706
  * first entry is always `0`) of every genuine off→on transition the
21726
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
21707
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
21727
21708
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
21728
21709
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
21729
21710
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -22247,6 +22228,7 @@ var KeyEventSchema = object({
22247
22228
  bestEventId: string(),
22248
22229
  /** Track lifetime in ms (lastSeen - firstSeen). */
22249
22230
  windowMs: number().optional(),
22231
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
22250
22232
  ...TrackFlagFields,
22251
22233
  ...TrackRetrainFields
22252
22234
  });
@@ -24175,8 +24157,10 @@ var RunnerCameraConfigSchema = object({
24175
24157
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24176
24158
  * analyzer providers) running on decoded frames in this runner.
24177
24159
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24178
- * analytics). The provider emits ProviderMotion
24179
- * events; the orchestrator forwards to `reportMotion`.
24160
+ * analytics). The provider emits its raw push as `ProviderMotion`
24161
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24162
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24163
+ * `reportMotion`.
24180
24164
  */
24181
24165
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24182
24166
  /**
@@ -24353,7 +24337,15 @@ var RunnerLocalLoadSchema = object({
24353
24337
  hasGpu: boolean(),
24354
24338
  inferenceBackend: string().optional(),
24355
24339
  cpuCores: number().optional()
24356
- })
24340
+ }),
24341
+ /**
24342
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24343
+ * runner never writes it. ABSENT = a runner older than D696, which still
24344
+ * writes the slice from its phase machine; the orchestrator does not write
24345
+ * while any runner node is absent-or-unanswered, so one slice never has two
24346
+ * writers.
24347
+ */
24348
+ motionSliceWriter: literal("orchestrator").optional()
24357
24349
  });
24358
24350
  /**
24359
24351
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -27018,7 +27010,7 @@ var ClipPlaybackSchema = object({
27018
27010
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
27019
27011
  * time the camera is awake for its own reasons — is deliberately not a member:
27020
27012
  * it was proposed, it is free on the battery, and the operator declined it on
27021
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
27013
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
27022
27014
  * D558 "Considered and not taken").
27023
27015
  */
27024
27016
  var ClipWakeSchema = _enum(["authorised"]);
@@ -27279,7 +27271,7 @@ DeviceType.Camera, method(object({
27279
27271
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
27280
27272
  * assumed the answer was a fan-out over everything a camera has. The
27281
27273
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
27282
- * solo"* — so the list is asked of one provider at a time and there is
27274
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
27283
27275
  * nothing to filter out of it.
27284
27276
  */
27285
27277
  provider: string().min(1)
@@ -29874,6 +29866,70 @@ onStatusChanged: { data: object({
29874
29866
  * whether persisting is worth a SQLite commit. */
29875
29867
  volatileStateFields: ["lastChangedAt"]
29876
29868
  };
29869
+ var DoorbellStatusSchema = object({
29870
+ /** Ms epoch of the last press. null = never observed since this provider started. */
29871
+ lastPressedAt: number().nullable(),
29872
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
29873
+ pressCountSinceStart: number()
29874
+ });
29875
+ var DoorbellPressEventSchema = object({
29876
+ deviceId: number(),
29877
+ timestamp: number()
29878
+ });
29879
+ /**
29880
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
29881
+ * they are the same cap:
29882
+ *
29883
+ * - **Native** providers, registered per device by a driver addon through
29884
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
29885
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
29886
+ * camera level). They emit `onPressed` on every firmware ring.
29887
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
29888
+ * the cap, its `lastPressedAt` rising from the sources the operator
29889
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
29890
+ * from that field's advance (`fromState`).
29891
+ *
29892
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
29893
+ */
29894
+ var doorbellCapability = {
29895
+ name: "doorbell",
29896
+ scope: "device",
29897
+ deviceNative: true,
29898
+ mode: "singleton",
29899
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
29900
+ methods: {},
29901
+ events: {
29902
+ /**
29903
+ * Fires once per physical press. Reolink delivers via Baichuan
29904
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
29905
+ * release/duration — it's a pulse.
29906
+ */
29907
+ onPressed: {
29908
+ data: DoorbellPressEventSchema,
29909
+ fromState: {
29910
+ field: "lastPressedAt",
29911
+ on: "advance"
29912
+ }
29913
+ } },
29914
+ status: {
29915
+ schema: DoorbellStatusSchema,
29916
+ kind: "push"
29917
+ },
29918
+ /**
29919
+ * Runtime-state slice — last press timestamp + lifetime press count.
29920
+ * Mirrored by the kernel and readable via
29921
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
29922
+ * without subscribing.
29923
+ */
29924
+ runtimeState: DoorbellStatusSchema,
29925
+ /**
29926
+ * 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.
29927
+ *
29928
+ * See `RuntimeStateDurability`. Enforced by
29929
+ * `scripts/check-runtime-state-durability.ts`.
29930
+ */
29931
+ durability: "restored"
29932
+ };
29877
29933
  /**
29878
29934
  * Enum-state sensor — a string value picked from a finite option set.
29879
29935
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -32018,9 +32074,9 @@ var MotionStatusSchema = object({
32018
32074
  /** Ms epoch of the last detected-true observation. Null if never detected. */
32019
32075
  lastDetectedAt: number().nullable(),
32020
32076
  /**
32021
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
32022
- * `null` while false and on every `Sensor` device (D475) — see that
32023
- * constant's doc for the one-authority rule.
32077
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
32078
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
32079
+ * device (D475) — see that constant's doc for the one-authority rule.
32024
32080
  *
32025
32081
  * ## Reading this field still arms nothing
32026
32082
  *
@@ -32038,34 +32094,31 @@ var MotionStatusSchema = object({
32038
32094
  * `addon-export-alexa/src/motion-clear-hold.ts` and
32039
32095
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
32040
32096
  *
32041
- * ## Who writes it
32042
- *
32043
- * - **Cameras** — the runner's phase machine, `active → watching` on
32044
- * `cooldown_expired`, which then writes this slice with
32045
- * `detected: false` (`handlePhaseChanged` in
32046
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
32047
- * matters most for the sources that only ever push a rising one:
32048
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
32049
- * a false.
32050
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
32051
- * provider pushes the false itself, from the upstream system's own
32052
- * state change. No phase machine is involved.
32053
- *
32054
- * ### The phase machine is CANONICAL, not sole — and that is a defect
32055
- *
32056
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
32057
- * phase machine is the sole writer for a camera. It is not.
32058
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
32059
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
32060
- * Hikvision's comment says why: it read THIS docblock, agreed the
32061
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
32062
- * two authorities can disagree about one slice, which this repo
32063
- * forbids, and the doc said otherwise — which is worse than saying
32064
- * nothing, because it reads as verification.
32065
- *
32066
- * This predates D475 and is not fixed there: the fix touches every
32067
- * camera provider. Recorded in D475's Consequences. Do not restore the
32068
- * "sole writer" wording without also removing the other writers.
32097
+ * ## Who writes it (D696)
32098
+ *
32099
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
32100
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
32101
+ * `camera-sensors/motion-slice.ts`), alongside the effective
32102
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
32103
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
32104
+ * device activity, as the camera's `motionSources` counts them. A source
32105
+ * that never sends a clear falls one window after its last `true`.
32106
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
32107
+ * writes this slice (not even a boot seed), and neither does the runner's
32108
+ * phase machine: its phase is "a session is attached" for every on-motion
32109
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
32110
+ * A provider's `isDetected` answers from the hub's slice.
32111
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32112
+ * imports) — the provider pushes both edges itself, from the upstream
32113
+ * system's own state change. That is the sensor's own fact.
32114
+ *
32115
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
32116
+ * `motion` slice; each sensor writer is a named exemption.
32117
+ *
32118
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
32119
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
32120
+ * it, every provider seeded it at boot, and every session left it
32121
+ * `detected: true` after its detach.
32069
32122
  */
32070
32123
  autoClearAfterMs: number().nullable()
32071
32124
  });
@@ -32137,11 +32190,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
32137
32190
  */
32138
32191
  runtimeState: MotionStatusSchema,
32139
32192
  /**
32140
- * Runtime-state durability: **session** — every writer of this slice
32193
+ * Runtime-state durability: **session** — the writer of this slice
32141
32194
  * writes only on an EDGE, so a restored `detected: true` would stay
32142
32195
  * frozen until the next one instead of being corrected. The next edge
32143
- * re-publishes the real state. (On who the writers are, and why there
32144
- * is more than one, see `autoClearAfterMs` above.)
32196
+ * re-publishes the real state, and the orchestrator re-publishes every
32197
+ * camera when it starts writing (D696; on who writes it, see
32198
+ * `autoClearAfterMs` above).
32145
32199
  *
32146
32200
  * See `RuntimeStateDurability`. Enforced by
32147
32201
  * `scripts/check-runtime-state-durability.ts`.
@@ -34524,8 +34578,7 @@ var ptzAutotrackCapability = {
34524
34578
  deviceNative: true,
34525
34579
  mode: "singleton",
34526
34580
  /**
34527
- * Two kinds of provider behind one name, the same shape `snapshot` and
34528
- * `doorbell` use:
34581
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
34529
34582
  *
34530
34583
  * - **Native**: the camera's own firmware autotrack, registered per device by
34531
34584
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -34533,7 +34586,7 @@ var ptzAutotrackCapability = {
34533
34586
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
34534
34587
  * which follows a subject with `ptz.move` pulses driven by the detection
34535
34588
  * pipeline. `defaultActive: false` — the operator binds it per camera in
34536
- * the bindings UI, exactly as `virtual-doorbell` is bound.
34589
+ * the bindings UI.
34537
34590
  *
34538
34591
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
34539
34592
  * one switch for the function either way. A camera never has both driving its
@@ -35208,7 +35261,7 @@ var ReadGopBytesResultSchema = object({
35208
35261
  /**
35209
35262
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
35210
35263
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
35211
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
35264
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
35212
35265
  * a replay needs several seconds of native pixels, not one frame.
35213
35266
  *
35214
35267
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -38572,6 +38625,7 @@ var zoneRulesCapability = {
38572
38625
  */
38573
38626
  durability: "restored"
38574
38627
  };
38628
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
38575
38629
  /**
38576
38630
  * Accessory device helpers — shared across drivers.
38577
38631
  *
@@ -39631,13 +39685,14 @@ var BaseDeviceProvider = class extends BaseAddon {
39631
39685
  async getStatus() {
39632
39686
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
39633
39687
  const summary = this.restoreFailureSummary();
39634
- if (summary === null) return {
39688
+ const base = {
39635
39689
  connected: true,
39636
- deviceCount: all.length
39690
+ deviceCount: all.length,
39691
+ motionSliceWriter: "orchestrator"
39637
39692
  };
39693
+ if (summary === null) return base;
39638
39694
  return {
39639
- connected: true,
39640
- deviceCount: all.length,
39695
+ ...base,
39641
39696
  error: summary
39642
39697
  };
39643
39698
  }
@@ -45073,6 +45128,12 @@ Object.freeze({
45073
45128
  addonId: null,
45074
45129
  access: "view"
45075
45130
  },
45131
+ "notificationRules.getAlarmSensors": {
45132
+ capName: "notification-rules",
45133
+ capScope: "system",
45134
+ addonId: null,
45135
+ access: "view"
45136
+ },
45076
45137
  "notificationRules.getClipRetentionAsks": {
45077
45138
  capName: "notification-rules",
45078
45139
  capScope: "system",
@@ -48651,6 +48712,11 @@ Object.freeze({
48651
48712
  }
48652
48713
  });
48653
48714
  Object.freeze({
48715
+ "accessories.getStatus": [{
48716
+ name: "deviceId",
48717
+ form: "single",
48718
+ optional: false
48719
+ }],
48654
48720
  "accessories.setChildHidden": [{
48655
48721
  name: "childDeviceId",
48656
48722
  form: "single",
@@ -48670,6 +48736,11 @@ Object.freeze({
48670
48736
  form: "single",
48671
48737
  optional: false
48672
48738
  }],
48739
+ "airQualitySensor.getStatus": [{
48740
+ name: "deviceId",
48741
+ form: "single",
48742
+ optional: false
48743
+ }],
48673
48744
  "alarmPanel.arm": [{
48674
48745
  name: "deviceId",
48675
48746
  form: "single",
@@ -48680,11 +48751,36 @@ Object.freeze({
48680
48751
  form: "single",
48681
48752
  optional: false
48682
48753
  }],
48754
+ "alarmPanel.getStatus": [{
48755
+ name: "deviceId",
48756
+ form: "single",
48757
+ optional: false
48758
+ }],
48683
48759
  "alarmPanel.trigger": [{
48684
48760
  name: "deviceId",
48685
48761
  form: "single",
48686
48762
  optional: false
48687
48763
  }],
48764
+ "ambientLightSensor.getStatus": [{
48765
+ name: "deviceId",
48766
+ form: "single",
48767
+ optional: false
48768
+ }],
48769
+ "audioAnalysis.applyDeviceSettingsPatch": [{
48770
+ name: "deviceId",
48771
+ form: "single",
48772
+ optional: false
48773
+ }],
48774
+ "audioAnalysis.getDeviceLiveContribution": [{
48775
+ name: "deviceId",
48776
+ form: "single",
48777
+ optional: false
48778
+ }],
48779
+ "audioAnalysis.getDeviceSettingsContribution": [{
48780
+ name: "deviceId",
48781
+ form: "single",
48782
+ optional: false
48783
+ }],
48688
48784
  "audioAnalysis.resolveDeviceSettings": [{
48689
48785
  name: "deviceId",
48690
48786
  form: "single",
@@ -48725,16 +48821,36 @@ Object.freeze({
48725
48821
  form: "single",
48726
48822
  optional: false
48727
48823
  }],
48824
+ "automationControl.getStatus": [{
48825
+ name: "deviceId",
48826
+ form: "single",
48827
+ optional: false
48828
+ }],
48728
48829
  "automationControl.trigger": [{
48729
48830
  name: "deviceId",
48730
48831
  form: "single",
48731
48832
  optional: false
48732
48833
  }],
48834
+ "battery.getStatus": [{
48835
+ name: "deviceId",
48836
+ form: "single",
48837
+ optional: false
48838
+ }],
48733
48839
  "battery.wakeForStream": [{
48734
48840
  name: "deviceId",
48735
48841
  form: "single",
48736
48842
  optional: false
48737
48843
  }],
48844
+ "binary.getStatus": [{
48845
+ name: "deviceId",
48846
+ form: "single",
48847
+ optional: false
48848
+ }],
48849
+ "brightness.getStatus": [{
48850
+ name: "deviceId",
48851
+ form: "single",
48852
+ optional: false
48853
+ }],
48738
48854
  "brightness.setBrightness": [{
48739
48855
  name: "deviceId",
48740
48856
  form: "single",
@@ -48750,6 +48866,26 @@ Object.freeze({
48750
48866
  form: "single",
48751
48867
  optional: false
48752
48868
  }],
48869
+ "cameraCredentials.getStatus": [{
48870
+ name: "deviceId",
48871
+ form: "single",
48872
+ optional: false
48873
+ }],
48874
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
48875
+ name: "deviceId",
48876
+ form: "single",
48877
+ optional: false
48878
+ }],
48879
+ "cameraGridLayout.getDeviceLiveContribution": [{
48880
+ name: "deviceId",
48881
+ form: "single",
48882
+ optional: false
48883
+ }],
48884
+ "cameraGridLayout.getDeviceSettingsContribution": [{
48885
+ name: "deviceId",
48886
+ form: "single",
48887
+ optional: false
48888
+ }],
48753
48889
  "cameraGridLayout.getLayout": [{
48754
48890
  name: "deviceId",
48755
48891
  form: "single",
@@ -48765,6 +48901,21 @@ Object.freeze({
48765
48901
  form: "single",
48766
48902
  optional: false
48767
48903
  }],
48904
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
48905
+ name: "deviceId",
48906
+ form: "single",
48907
+ optional: false
48908
+ }],
48909
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
48910
+ name: "deviceId",
48911
+ form: "single",
48912
+ optional: false
48913
+ }],
48914
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
48915
+ name: "deviceId",
48916
+ form: "single",
48917
+ optional: false
48918
+ }],
48768
48919
  "cameraStreams.getBrokerStreams": [{
48769
48920
  name: "deviceId",
48770
48921
  form: "single",
@@ -48790,6 +48941,16 @@ Object.freeze({
48790
48941
  form: "single",
48791
48942
  optional: false
48792
48943
  }],
48944
+ "carbonMonoxide.getStatus": [{
48945
+ name: "deviceId",
48946
+ form: "single",
48947
+ optional: false
48948
+ }],
48949
+ "climateControl.getStatus": [{
48950
+ name: "deviceId",
48951
+ form: "single",
48952
+ optional: false
48953
+ }],
48793
48954
  "climateControl.setFanMode": [{
48794
48955
  name: "deviceId",
48795
48956
  form: "single",
@@ -48830,16 +48991,41 @@ Object.freeze({
48830
48991
  form: "single",
48831
48992
  optional: false
48832
48993
  }],
48994
+ "color.getStatus": [{
48995
+ name: "deviceId",
48996
+ form: "single",
48997
+ optional: false
48998
+ }],
48833
48999
  "color.setColor": [{
48834
49000
  name: "deviceId",
48835
49001
  form: "single",
48836
49002
  optional: false
48837
49003
  }],
49004
+ "connectivity.getStatus": [{
49005
+ name: "deviceId",
49006
+ form: "single",
49007
+ optional: false
49008
+ }],
49009
+ "consumables.getStatus": [{
49010
+ name: "deviceId",
49011
+ form: "single",
49012
+ optional: false
49013
+ }],
48838
49014
  "consumables.reset": [{
48839
49015
  name: "deviceId",
48840
49016
  form: "single",
48841
49017
  optional: false
48842
49018
  }],
49019
+ "contact.getStatus": [{
49020
+ name: "deviceId",
49021
+ form: "single",
49022
+ optional: false
49023
+ }],
49024
+ "control.getStatus": [{
49025
+ name: "deviceId",
49026
+ form: "single",
49027
+ optional: false
49028
+ }],
48843
49029
  "control.setValue": [{
48844
49030
  name: "deviceId",
48845
49031
  form: "single",
@@ -48850,6 +49036,11 @@ Object.freeze({
48850
49036
  form: "single",
48851
49037
  optional: false
48852
49038
  }],
49039
+ "cover.getStatus": [{
49040
+ name: "deviceId",
49041
+ form: "single",
49042
+ optional: false
49043
+ }],
48853
49044
  "cover.open": [{
48854
49045
  name: "deviceId",
48855
49046
  form: "single",
@@ -48875,6 +49066,11 @@ Object.freeze({
48875
49066
  form: "single",
48876
49067
  optional: false
48877
49068
  }],
49069
+ "dayNight.getStatus": [{
49070
+ name: "deviceId",
49071
+ form: "single",
49072
+ optional: false
49073
+ }],
48878
49074
  "dayNight.setSettings": [{
48879
49075
  name: "deviceId",
48880
49076
  form: "single",
@@ -48885,11 +49081,31 @@ Object.freeze({
48885
49081
  form: "single",
48886
49082
  optional: true
48887
49083
  }],
49084
+ "detectionPipeline.applyDeviceSettingsPatch": [{
49085
+ name: "deviceId",
49086
+ form: "single",
49087
+ optional: false
49088
+ }],
49089
+ "detectionPipeline.getDeviceLiveContribution": [{
49090
+ name: "deviceId",
49091
+ form: "single",
49092
+ optional: false
49093
+ }],
49094
+ "detectionPipeline.getDeviceSettingsContribution": [{
49095
+ name: "deviceId",
49096
+ form: "single",
49097
+ optional: false
49098
+ }],
48888
49099
  "deviceAdminLink.getAdminLink": [{
48889
49100
  name: "deviceId",
48890
49101
  form: "single",
48891
49102
  optional: false
48892
49103
  }],
49104
+ "deviceAdoption.getStatus": [{
49105
+ name: "deviceId",
49106
+ form: "single",
49107
+ optional: false
49108
+ }],
48893
49109
  "deviceAdoption.release": [{
48894
49110
  name: "camDeviceId",
48895
49111
  form: "single",
@@ -48905,6 +49121,11 @@ Object.freeze({
48905
49121
  form: "single",
48906
49122
  optional: false
48907
49123
  }],
49124
+ "deviceDiscovery.getStatus": [{
49125
+ name: "deviceId",
49126
+ form: "single",
49127
+ optional: false
49128
+ }],
48908
49129
  "deviceDiscovery.listDiscovered": [{
48909
49130
  name: "deviceId",
48910
49131
  form: "single",
@@ -48924,6 +49145,21 @@ Object.freeze({
48924
49145
  form: "single",
48925
49146
  optional: false
48926
49147
  }],
49148
+ "deviceExport.applyDeviceSettingsPatch": [{
49149
+ name: "deviceId",
49150
+ form: "single",
49151
+ optional: false
49152
+ }],
49153
+ "deviceExport.getDeviceLiveContribution": [{
49154
+ name: "deviceId",
49155
+ form: "single",
49156
+ optional: false
49157
+ }],
49158
+ "deviceExport.getDeviceSettingsContribution": [{
49159
+ name: "deviceId",
49160
+ form: "single",
49161
+ optional: false
49162
+ }],
48927
49163
  "deviceExtension.listCandidates": [{
48928
49164
  name: "deviceId",
48929
49165
  form: "single",
@@ -49272,6 +49508,26 @@ Object.freeze({
49272
49508
  form: "single",
49273
49509
  optional: false
49274
49510
  }],
49511
+ "deviceStatus.getStatus": [{
49512
+ name: "deviceId",
49513
+ form: "single",
49514
+ optional: false
49515
+ }],
49516
+ "doorbell.getStatus": [{
49517
+ name: "deviceId",
49518
+ form: "single",
49519
+ optional: false
49520
+ }],
49521
+ "enumSensor.getStatus": [{
49522
+ name: "deviceId",
49523
+ form: "single",
49524
+ optional: false
49525
+ }],
49526
+ "eventEmitter.getStatus": [{
49527
+ name: "deviceId",
49528
+ form: "single",
49529
+ optional: false
49530
+ }],
49275
49531
  "faceGallery.getFaceByTrack": [{
49276
49532
  name: "deviceId",
49277
49533
  form: "single",
@@ -49286,6 +49542,11 @@ Object.freeze({
49286
49542
  form: "array",
49287
49543
  optional: true
49288
49544
  }],
49545
+ "fanControl.getStatus": [{
49546
+ name: "deviceId",
49547
+ form: "single",
49548
+ optional: false
49549
+ }],
49289
49550
  "fanControl.setDirection": [{
49290
49551
  name: "deviceId",
49291
49552
  form: "single",
@@ -49306,6 +49567,26 @@ Object.freeze({
49306
49567
  form: "single",
49307
49568
  optional: false
49308
49569
  }],
49570
+ "featureProbe.getStatus": [{
49571
+ name: "deviceId",
49572
+ form: "single",
49573
+ optional: false
49574
+ }],
49575
+ "flood.getStatus": [{
49576
+ name: "deviceId",
49577
+ form: "single",
49578
+ optional: false
49579
+ }],
49580
+ "gas.getStatus": [{
49581
+ name: "deviceId",
49582
+ form: "single",
49583
+ optional: false
49584
+ }],
49585
+ "humidifier.getStatus": [{
49586
+ name: "deviceId",
49587
+ form: "single",
49588
+ optional: false
49589
+ }],
49309
49590
  "humidifier.setMode": [{
49310
49591
  name: "deviceId",
49311
49592
  form: "single",
@@ -49321,11 +49602,26 @@ Object.freeze({
49321
49602
  form: "single",
49322
49603
  optional: false
49323
49604
  }],
49605
+ "humiditySensor.getStatus": [{
49606
+ name: "deviceId",
49607
+ form: "single",
49608
+ optional: false
49609
+ }],
49610
+ "image.getStatus": [{
49611
+ name: "deviceId",
49612
+ form: "single",
49613
+ optional: false
49614
+ }],
49324
49615
  "imageSettings.getOptions": [{
49325
49616
  name: "deviceId",
49326
49617
  form: "single",
49327
49618
  optional: false
49328
49619
  }],
49620
+ "imageSettings.getStatus": [{
49621
+ name: "deviceId",
49622
+ form: "single",
49623
+ optional: false
49624
+ }],
49329
49625
  "imageSettings.setSettings": [{
49330
49626
  name: "deviceId",
49331
49627
  form: "single",
@@ -49336,6 +49632,11 @@ Object.freeze({
49336
49632
  form: "single",
49337
49633
  optional: false
49338
49634
  }],
49635
+ "intercom.getStatus": [{
49636
+ name: "deviceId",
49637
+ form: "single",
49638
+ optional: false
49639
+ }],
49339
49640
  "intercom.handleAnswer": [{
49340
49641
  name: "deviceId",
49341
49642
  form: "single",
@@ -49366,6 +49667,11 @@ Object.freeze({
49366
49667
  form: "single",
49367
49668
  optional: false
49368
49669
  }],
49670
+ "lawnMowerControl.getStatus": [{
49671
+ name: "deviceId",
49672
+ form: "single",
49673
+ optional: false
49674
+ }],
49369
49675
  "lawnMowerControl.pause": [{
49370
49676
  name: "deviceId",
49371
49677
  form: "single",
@@ -49376,6 +49682,11 @@ Object.freeze({
49376
49682
  form: "single",
49377
49683
  optional: false
49378
49684
  }],
49685
+ "lockControl.getStatus": [{
49686
+ name: "deviceId",
49687
+ form: "single",
49688
+ optional: false
49689
+ }],
49379
49690
  "lockControl.lock": [{
49380
49691
  name: "deviceId",
49381
49692
  form: "single",
@@ -49391,6 +49702,11 @@ Object.freeze({
49391
49702
  form: "single",
49392
49703
  optional: false
49393
49704
  }],
49705
+ "mediaPlayer.getStatus": [{
49706
+ name: "deviceId",
49707
+ form: "single",
49708
+ optional: false
49709
+ }],
49394
49710
  "mediaPlayer.next": [{
49395
49711
  name: "deviceId",
49396
49712
  form: "single",
@@ -49451,6 +49767,11 @@ Object.freeze({
49451
49767
  form: "single",
49452
49768
  optional: false
49453
49769
  }],
49770
+ "motion.getStatus": [{
49771
+ name: "deviceId",
49772
+ form: "single",
49773
+ optional: false
49774
+ }],
49454
49775
  "motion.isDetected": [{
49455
49776
  name: "deviceId",
49456
49777
  form: "single",
@@ -49461,11 +49782,31 @@ Object.freeze({
49461
49782
  form: "single",
49462
49783
  optional: false
49463
49784
  }],
49785
+ "motionDetection.applyDeviceSettingsPatch": [{
49786
+ name: "deviceId",
49787
+ form: "single",
49788
+ optional: false
49789
+ }],
49790
+ "motionDetection.getDeviceLiveContribution": [{
49791
+ name: "deviceId",
49792
+ form: "single",
49793
+ optional: false
49794
+ }],
49795
+ "motionDetection.getDeviceSettingsContribution": [{
49796
+ name: "deviceId",
49797
+ form: "single",
49798
+ optional: false
49799
+ }],
49464
49800
  "motionDetection.removeCamera": [{
49465
49801
  name: "deviceId",
49466
49802
  form: "single",
49467
49803
  optional: false
49468
49804
  }],
49805
+ "motionTrigger.getStatus": [{
49806
+ name: "deviceId",
49807
+ form: "single",
49808
+ optional: false
49809
+ }],
49469
49810
  "motionTrigger.setMotionTrigger": [{
49470
49811
  name: "deviceId",
49471
49812
  form: "single",
@@ -49476,6 +49817,11 @@ Object.freeze({
49476
49817
  form: "single",
49477
49818
  optional: false
49478
49819
  }],
49820
+ "motionZones.getStatus": [{
49821
+ name: "deviceId",
49822
+ form: "single",
49823
+ optional: false
49824
+ }],
49479
49825
  "motionZones.setZone": [{
49480
49826
  name: "deviceId",
49481
49827
  form: "single",
@@ -49486,6 +49832,11 @@ Object.freeze({
49486
49832
  form: "single",
49487
49833
  optional: false
49488
49834
  }],
49835
+ "nativeObjectDetection.getStatus": [{
49836
+ name: "deviceId",
49837
+ form: "single",
49838
+ optional: false
49839
+ }],
49489
49840
  "nativeObjectDetection.setEnabled": [{
49490
49841
  name: "deviceId",
49491
49842
  form: "single",
@@ -49501,6 +49852,11 @@ Object.freeze({
49501
49852
  form: "single",
49502
49853
  optional: false
49503
49854
  }],
49855
+ "navigation.getStatus": [{
49856
+ name: "deviceId",
49857
+ form: "single",
49858
+ optional: false
49859
+ }],
49504
49860
  "navigation.goToPoint": [{
49505
49861
  name: "deviceId",
49506
49862
  form: "single",
@@ -49546,6 +49902,11 @@ Object.freeze({
49546
49902
  form: "single",
49547
49903
  optional: false
49548
49904
  }],
49905
+ "networkLink.getStatus": [{
49906
+ name: "deviceId",
49907
+ form: "single",
49908
+ optional: false
49909
+ }],
49549
49910
  "networkQuality.getDeviceStats": [{
49550
49911
  name: "deviceId",
49551
49912
  form: "single",
@@ -49556,6 +49917,11 @@ Object.freeze({
49556
49917
  form: "single",
49557
49918
  optional: false
49558
49919
  }],
49920
+ "notificationRules.getAlarmSensors": [{
49921
+ name: "deviceIds",
49922
+ form: "array",
49923
+ optional: false
49924
+ }],
49559
49925
  "notificationRules.setDeviceMuted": [{
49560
49926
  name: "deviceId",
49561
49927
  form: "single",
@@ -49566,11 +49932,26 @@ Object.freeze({
49566
49932
  form: "single",
49567
49933
  optional: false
49568
49934
  }],
49935
+ "notifier.getStatus": [{
49936
+ name: "deviceId",
49937
+ form: "single",
49938
+ optional: false
49939
+ }],
49569
49940
  "notifier.send": [{
49570
49941
  name: "deviceId",
49571
49942
  form: "single",
49572
49943
  optional: false
49573
49944
  }],
49945
+ "numericSensor.getStatus": [{
49946
+ name: "deviceId",
49947
+ form: "single",
49948
+ optional: false
49949
+ }],
49950
+ "osd.getStatus": [{
49951
+ name: "deviceId",
49952
+ form: "single",
49953
+ optional: false
49954
+ }],
49574
49955
  "osd.setOverlay": [{
49575
49956
  name: "deviceId",
49576
49957
  form: "single",
@@ -49630,6 +50011,11 @@ Object.freeze({
49630
50011
  form: "single",
49631
50012
  optional: false
49632
50013
  }],
50014
+ "petFeeder.getStatus": [{
50015
+ name: "deviceId",
50016
+ form: "single",
50017
+ optional: false
50018
+ }],
49633
50019
  "petFeeder.markFoodReplenished": [{
49634
50020
  name: "deviceId",
49635
50021
  form: "single",
@@ -49665,6 +50051,11 @@ Object.freeze({
49665
50051
  form: "single",
49666
50052
  optional: false
49667
50053
  }],
50054
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
50055
+ name: "deviceId",
50056
+ form: "single",
50057
+ optional: false
50058
+ }],
49668
50059
  "pipelineAnalytics.clearTrackRelation": [{
49669
50060
  name: "deviceId",
49670
50061
  form: "single",
@@ -49705,6 +50096,16 @@ Object.freeze({
49705
50096
  form: "single",
49706
50097
  optional: false
49707
50098
  }],
50099
+ "pipelineAnalytics.getDeviceLiveContribution": [{
50100
+ name: "deviceId",
50101
+ form: "single",
50102
+ optional: false
50103
+ }],
50104
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
50105
+ name: "deviceId",
50106
+ form: "single",
50107
+ optional: false
50108
+ }],
49708
50109
  "pipelineAnalytics.getEventDensity": [{
49709
50110
  name: "deviceId",
49710
50111
  form: "single",
@@ -49920,6 +50321,11 @@ Object.freeze({
49920
50321
  form: "single",
49921
50322
  optional: true
49922
50323
  }],
50324
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
50325
+ name: "deviceId",
50326
+ form: "single",
50327
+ optional: false
50328
+ }],
49923
50329
  "pipelineOrchestrator.assignAudio": [{
49924
50330
  name: "deviceId",
49925
50331
  form: "single",
@@ -49965,6 +50371,16 @@ Object.freeze({
49965
50371
  form: "single",
49966
50372
  optional: false
49967
50373
  }],
50374
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
50375
+ name: "deviceId",
50376
+ form: "single",
50377
+ optional: false
50378
+ }],
50379
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
50380
+ name: "deviceId",
50381
+ form: "single",
50382
+ optional: false
50383
+ }],
49968
50384
  "pipelineOrchestrator.getPipelineAssignment": [{
49969
50385
  name: "deviceId",
49970
50386
  form: "single",
@@ -50085,11 +50501,31 @@ Object.freeze({
50085
50501
  form: "single",
50086
50502
  optional: true
50087
50503
  }],
50504
+ "powerMeter.getStatus": [{
50505
+ name: "deviceId",
50506
+ form: "single",
50507
+ optional: false
50508
+ }],
50509
+ "presence.getStatus": [{
50510
+ name: "deviceId",
50511
+ form: "single",
50512
+ optional: false
50513
+ }],
50514
+ "pressureSensor.getStatus": [{
50515
+ name: "deviceId",
50516
+ form: "single",
50517
+ optional: false
50518
+ }],
50088
50519
  "privacyMask.getOptions": [{
50089
50520
  name: "deviceId",
50090
50521
  form: "single",
50091
50522
  optional: false
50092
50523
  }],
50524
+ "privacyMask.getStatus": [{
50525
+ name: "deviceId",
50526
+ form: "single",
50527
+ optional: false
50528
+ }],
50093
50529
  "privacyMask.setAudioEnabled": [{
50094
50530
  name: "deviceId",
50095
50531
  form: "single",
@@ -50140,6 +50576,11 @@ Object.freeze({
50140
50576
  form: "single",
50141
50577
  optional: false
50142
50578
  }],
50579
+ "ptz.getStatus": [{
50580
+ name: "deviceId",
50581
+ form: "single",
50582
+ optional: false
50583
+ }],
50143
50584
  "ptz.goHome": [{
50144
50585
  name: "deviceId",
50145
50586
  form: "single",
@@ -50230,6 +50671,11 @@ Object.freeze({
50230
50671
  form: "single",
50231
50672
  optional: false
50232
50673
  }],
50674
+ "recordingArchive.applyDeviceSettingsPatch": [{
50675
+ name: "deviceId",
50676
+ form: "single",
50677
+ optional: false
50678
+ }],
50233
50679
  "recordingArchive.deleteFootprint": [{
50234
50680
  name: "deviceId",
50235
50681
  form: "single",
@@ -50250,6 +50696,21 @@ Object.freeze({
50250
50696
  form: "single",
50251
50697
  optional: false
50252
50698
  }],
50699
+ "recordingArchive.getDeviceLiveContribution": [{
50700
+ name: "deviceId",
50701
+ form: "single",
50702
+ optional: false
50703
+ }],
50704
+ "recordingArchive.getDeviceSettingsContribution": [{
50705
+ name: "deviceId",
50706
+ form: "single",
50707
+ optional: false
50708
+ }],
50709
+ "recordingArchive.getStatus": [{
50710
+ name: "deviceId",
50711
+ form: "single",
50712
+ optional: false
50713
+ }],
50253
50714
  "recordingArchive.listOpsLog": [{
50254
50715
  name: "deviceId",
50255
50716
  form: "single",
@@ -50335,6 +50796,11 @@ Object.freeze({
50335
50796
  form: "single",
50336
50797
  optional: false
50337
50798
  }],
50799
+ "recordingOnboard.getStatus": [{
50800
+ name: "deviceId",
50801
+ form: "single",
50802
+ optional: false
50803
+ }],
50338
50804
  "recordingOnboard.setSettings": [{
50339
50805
  name: "deviceId",
50340
50806
  form: "single",
@@ -50365,6 +50831,11 @@ Object.freeze({
50365
50831
  form: "single",
50366
50832
  optional: false
50367
50833
  }],
50834
+ "sceneMonitor.getStatus": [{
50835
+ name: "deviceId",
50836
+ form: "single",
50837
+ optional: false
50838
+ }],
50368
50839
  "sceneMonitor.listScenes": [{
50369
50840
  name: "deviceId",
50370
50841
  form: "single",
@@ -50390,6 +50861,11 @@ Object.freeze({
50390
50861
  form: "single",
50391
50862
  optional: false
50392
50863
  }],
50864
+ "scriptRunner.getStatus": [{
50865
+ name: "deviceId",
50866
+ form: "single",
50867
+ optional: false
50868
+ }],
50393
50869
  "scriptRunner.run": [{
50394
50870
  name: "deviceId",
50395
50871
  form: "single",
@@ -50400,11 +50876,31 @@ Object.freeze({
50400
50876
  form: "single",
50401
50877
  optional: false
50402
50878
  }],
50879
+ "smoke.getStatus": [{
50880
+ name: "deviceId",
50881
+ form: "single",
50882
+ optional: false
50883
+ }],
50884
+ "snapshot.applyDeviceSettingsPatch": [{
50885
+ name: "deviceId",
50886
+ form: "single",
50887
+ optional: false
50888
+ }],
50403
50889
  "snapshot.getDebugState": [{
50404
50890
  name: "deviceId",
50405
50891
  form: "single",
50406
50892
  optional: false
50407
50893
  }],
50894
+ "snapshot.getDeviceLiveContribution": [{
50895
+ name: "deviceId",
50896
+ form: "single",
50897
+ optional: false
50898
+ }],
50899
+ "snapshot.getDeviceSettingsContribution": [{
50900
+ name: "deviceId",
50901
+ form: "single",
50902
+ optional: false
50903
+ }],
50408
50904
  "snapshot.getSnapshot": [{
50409
50905
  name: "deviceId",
50410
50906
  form: "single",
@@ -50421,6 +50917,11 @@ Object.freeze({
50421
50917
  form: "array",
50422
50918
  optional: false
50423
50919
  }],
50920
+ "snapshot.getStatus": [{
50921
+ name: "deviceId",
50922
+ form: "single",
50923
+ optional: false
50924
+ }],
50424
50925
  "snapshot.invalidateCache": [{
50425
50926
  name: "deviceId",
50426
50927
  form: "single",
@@ -50431,6 +50932,11 @@ Object.freeze({
50431
50932
  form: "single",
50432
50933
  optional: false
50433
50934
  }],
50935
+ "streamBroker.applyDeviceSettingsPatch": [{
50936
+ name: "deviceId",
50937
+ form: "single",
50938
+ optional: false
50939
+ }],
50434
50940
  "streamBroker.assignProfile": [{
50435
50941
  name: "deviceId",
50436
50942
  form: "single",
@@ -50446,6 +50952,16 @@ Object.freeze({
50446
50952
  form: "single",
50447
50953
  optional: false
50448
50954
  }],
50955
+ "streamBroker.getDeviceLiveContribution": [{
50956
+ name: "deviceId",
50957
+ form: "single",
50958
+ optional: false
50959
+ }],
50960
+ "streamBroker.getDeviceSettingsContribution": [{
50961
+ name: "deviceId",
50962
+ form: "single",
50963
+ optional: false
50964
+ }],
50449
50965
  "streamBroker.getStreamWithCodec": [{
50450
50966
  name: "deviceId",
50451
50967
  form: "single",
@@ -50506,16 +51022,46 @@ Object.freeze({
50506
51022
  form: "single",
50507
51023
  optional: false
50508
51024
  }],
51025
+ "streamParams.getStatus": [{
51026
+ name: "deviceId",
51027
+ form: "single",
51028
+ optional: false
51029
+ }],
50509
51030
  "streamParams.setProfile": [{
50510
51031
  name: "deviceId",
50511
51032
  form: "single",
50512
51033
  optional: false
50513
51034
  }],
51035
+ "switch.getStatus": [{
51036
+ name: "deviceId",
51037
+ form: "single",
51038
+ optional: false
51039
+ }],
50514
51040
  "switch.setState": [{
50515
51041
  name: "deviceId",
50516
51042
  form: "single",
50517
51043
  optional: false
50518
51044
  }],
51045
+ "tamper.getStatus": [{
51046
+ name: "deviceId",
51047
+ form: "single",
51048
+ optional: false
51049
+ }],
51050
+ "temperatureSensor.getStatus": [{
51051
+ name: "deviceId",
51052
+ form: "single",
51053
+ optional: false
51054
+ }],
51055
+ "update.getStatus": [{
51056
+ name: "deviceId",
51057
+ form: "single",
51058
+ optional: false
51059
+ }],
51060
+ "vacuumControl.getStatus": [{
51061
+ name: "deviceId",
51062
+ form: "single",
51063
+ optional: false
51064
+ }],
50519
51065
  "vacuumControl.locate": [{
50520
51066
  name: "deviceId",
50521
51067
  form: "single",
@@ -50551,6 +51097,11 @@ Object.freeze({
50551
51097
  form: "single",
50552
51098
  optional: false
50553
51099
  }],
51100
+ "valve.getStatus": [{
51101
+ name: "deviceId",
51102
+ form: "single",
51103
+ optional: false
51104
+ }],
50554
51105
  "valve.open": [{
50555
51106
  name: "deviceId",
50556
51107
  form: "single",
@@ -50566,6 +51117,11 @@ Object.freeze({
50566
51117
  form: "single",
50567
51118
  optional: false
50568
51119
  }],
51120
+ "vibration.getStatus": [{
51121
+ name: "deviceId",
51122
+ form: "single",
51123
+ optional: false
51124
+ }],
50569
51125
  "videoclips.dialClipStream": [{
50570
51126
  name: "deviceId",
50571
51127
  form: "single",
@@ -50601,6 +51157,11 @@ Object.freeze({
50601
51157
  form: "single",
50602
51158
  optional: false
50603
51159
  }],
51160
+ "waterHeater.getStatus": [{
51161
+ name: "deviceId",
51162
+ form: "single",
51163
+ optional: false
51164
+ }],
50604
51165
  "waterHeater.setAway": [{
50605
51166
  name: "deviceId",
50606
51167
  form: "single",
@@ -50616,6 +51177,11 @@ Object.freeze({
50616
51177
  form: "single",
50617
51178
  optional: false
50618
51179
  }],
51180
+ "weather.getStatus": [{
51181
+ name: "deviceId",
51182
+ form: "single",
51183
+ optional: false
51184
+ }],
50619
51185
  "webrtcSession.addIceCandidate": [{
50620
51186
  name: "deviceId",
50621
51187
  form: "single",
@@ -51353,7 +51919,7 @@ var PreviewTextField = string().max(200);
51353
51919
  * Whether the notification's preview is a STILL or a short animation.
51354
51920
  *
51355
51921
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
51356
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
51922
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
51357
51923
  * night reads better as three seconds of motion than as one frame of it. Both
51358
51924
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
51359
51925
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -51491,6 +52057,7 @@ TimelapseRuleInputSchema.extend({
51491
52057
  createdAt: number(),
51492
52058
  updatedAt: number()
51493
52059
  });
52060
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
51494
52061
  object({
51495
52062
  /**
51496
52063
  * Fraction of the box's own size added on EACH side before cutting.