@camstack/addon-provider-rtsp 1.2.117 → 1.2.118

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
@@ -1,5 +1,5 @@
1
1
  import net from "node:net";
2
- //#region ../types/dist/event-category-C5xZWqz6.mjs
2
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -532,6 +532,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
532
532
  */
533
533
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
534
534
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
535
+ /**
536
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
537
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
538
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
539
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
540
+ * for a camera with no attached sensor). Providers must not emit
541
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
542
+ * keeps it so (camera-grid is a named, deferred exception).
543
+ */
535
544
  EventCategory["ProviderMotion"] = "provider.motion";
536
545
  EventCategory["ProviderDetection"] = "provider.detection";
537
546
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5370,7 +5379,7 @@ var ZodIssueCode = {
5370
5379
  var ZodFirstPartyTypeKind;
5371
5380
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5372
5381
  //#endregion
5373
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5382
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5374
5383
  /**
5375
5384
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5376
5385
  * window to float samples (D455).
@@ -7413,7 +7422,7 @@ function errMsg(err) {
7413
7422
  return String(err);
7414
7423
  }
7415
7424
  //#endregion
7416
- //#region ../types/dist/composition-Dq42XWp0.mjs
7425
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
7417
7426
  /**
7418
7427
  * The ffmpeg build every CamStack node downloads, per platform and arch.
7419
7428
  *
@@ -7467,21 +7476,20 @@ function portable(target) {
7467
7476
  }
7468
7477
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
7469
7478
  /**
7470
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7471
- * valutatore puro del suo FRONTE.
7479
+ * THE table "which boolean of this device type counts as HIGH", and the
7480
+ * pure evaluator of its EDGE.
7472
7481
  *
7473
- * Viveva dentro il builtin virtual-doorbell
7474
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7475
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7476
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7477
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7478
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7479
- * SPOSTA qui e il doorbell la ri-esporta.
7482
+ * ONE table for everyone who asks "is this device HIGH?": the
7483
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
7484
+ * sensor markers, the orchestrator's camera-sensors bridge and
7485
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
7486
+ * A second copy would diverge at the first cap added, and the symptom — "the
7487
+ * sensor rings the doorbell but does not record" — is exactly D62.
7480
7488
  *
7481
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7482
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7483
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7484
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7489
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
7490
+ * two must not be unified: that one answers "what is the state WORD for a
7491
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
7492
+ * boolean's EDGE counts". Deliberately different vocabularies.
7485
7493
  */
7486
7494
  /**
7487
7495
  * Known binary / switch source caps → the boolean slice field whose
@@ -9122,22 +9130,22 @@ var CLASS_MAP_MACRO_TARGETS = [
9122
9130
  "package"
9123
9131
  ];
9124
9132
  /**
9125
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
9126
- * un operatore può selezionare.
9133
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
9134
+ * an operator can select.
9127
9135
  *
9128
- * Sono le tre offerte dallo step `object-detection`
9136
+ * They are the three offered by the `object-detection` step
9129
9137
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
9130
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
9131
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
9132
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
9133
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
9138
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
9139
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
9140
+ * `package-detection`, whose enablement is driven by zones, and offering the
9141
+ * same word twice has already made an operator turn on the COCO proxy
9134
9142
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
9135
9143
  *
9136
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
9137
- * dello step e una seconda volta come union `FirstLevelMacro`
9138
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
9139
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
9140
- * successiva.
9144
+ * ONE list. Before today the same three were hand-written in the step's offer
9145
+ * and a second time as the union `FirstLevelMacro`
9146
+ * (`types/detection.ts`); a third copy for the recording trigger
9147
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
9148
+ * invisible.
9141
9149
  */
9142
9150
  var FIRST_LEVEL_MACRO_CLASSES = [
9143
9151
  "person",
@@ -9202,17 +9210,17 @@ var RecordingStorageModeSchema = _enum([
9202
9210
  "on-device-decision"
9203
9211
  ]);
9204
9212
  /**
9205
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
9206
- * tre offerte dallo step `object-detection`, da UNA lista
9213
+ * The macro classes that can open a recording window — the same
9214
+ * three offered by the `object-detection` step, from ONE list
9207
9215
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
9208
9216
  */
9209
9217
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
9210
9218
  /**
9211
- * True quando `values` non ripete un elemento.
9219
+ * True when `values` does not repeat an element.
9212
9220
  *
9213
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
9214
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
9215
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
9221
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
9222
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
9223
+ * would count its windows twice in `segmentMissedByMs`.
9216
9224
  */
9217
9225
  var noDuplicates = (values) => new Set(values).size === values.length;
9218
9226
  /** Which detectors trigger an `events`-mode band. */
@@ -9220,34 +9228,34 @@ var RecordingTriggersSchema = object({
9220
9228
  motion: boolean().optional(),
9221
9229
  audioThresholdDbfs: number().optional(),
9222
9230
  /**
9223
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
9224
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
9225
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
9226
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
9231
+ * The macro classes whose detection opens a window. ABSENT = the source
9232
+ * is not listened to; an EMPTY array is rejected, because "events band, object
9233
+ * trigger on, no class" is the same shape "enabled and records
9234
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
9227
9235
  *
9228
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
9229
- * quelle che hanno attraversato `enabledMacroClasses`, i
9230
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
9231
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
9232
- * finestre — vedi `recorder/object-trigger.ts`.
9236
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
9237
+ * those that went through `enabledMacroClasses`, the
9238
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
9239
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
9240
+ * windows — see `recorder/object-trigger.ts`.
9233
9241
  */
9234
9242
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
9235
9243
  /**
9236
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
9237
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
9244
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
9245
+ * is not listened to; an empty array is rejected for the same reason as
9238
9246
  * `objectClasses`.
9239
9247
  *
9240
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
9241
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
9242
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
9243
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9244
- * device (D12) — mai un elenco globale di cap.
9248
+ * These are SOURCE device ids, not cameras: the band names them, so the
9249
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
9250
+ * does no RPC. The OFFER from which the operator picks them is another question, and
9251
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9252
+ * device (D12) — never a global list of caps.
9245
9253
  *
9246
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9247
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9248
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9249
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
9250
- * registrare.
9254
+ * What "high" means depends on the device TYPE and is not decided here:
9255
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
9256
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
9257
+ * the level: a contact found already open at runner restart does not
9258
+ * record.
9251
9259
  */
9252
9260
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9253
9261
  });
@@ -10324,7 +10332,7 @@ var DecoderSessionConfigSchema = object({
10324
10332
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
10325
10333
  * thing: the logging settings document on the `system` cap. Two authorities
10326
10334
  * over the values is the exact defect
10327
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
10335
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
10328
10336
  * remove; re-introducing it from the cure side would be grotesque.
10329
10337
  *
10330
10338
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -12035,7 +12043,7 @@ var BrokerStatusEnum = _enum([
12035
12043
  "unreachable",
12036
12044
  "error"
12037
12045
  ]);
12038
- var BrokerInfoSchema$1 = object({
12046
+ var BrokerInfoSchema = object({
12039
12047
  /** Stable broker id. Persisted; survives addon restarts. */
12040
12048
  id: string(),
12041
12049
  /** Addon id of the provider that OWNS this broker.
@@ -12168,7 +12176,7 @@ var GetStateInputSchema = object({
12168
12176
  * HA: entity_id (returns the cached entity state). */
12169
12177
  key: string()
12170
12178
  });
12171
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12179
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12172
12180
  kind: "mutation",
12173
12181
  auth: "admin"
12174
12182
  }), method(RemoveInputSchema, _void(), {
@@ -13879,7 +13887,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
13879
13887
  *
13880
13888
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
13881
13889
  * was wrong — corrected 2026-08-26 after the hop map
13882
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
13890
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
13883
13891
  * There is **no Zod parse at all** between the door and the engine: the
13884
13892
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
13885
13893
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -14742,7 +14750,17 @@ var SiteZoneSchema = object({
14742
14750
  var ProviderStatusSchema = object({
14743
14751
  connected: boolean(),
14744
14752
  deviceCount: number(),
14745
- error: string().optional()
14753
+ error: string().optional(),
14754
+ /**
14755
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14756
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14757
+ * which every provider bundles, so only a provider BUILT from D696-amended
14758
+ * code says it. ABSENT means an older provider that may still write it (raw
14759
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14760
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14761
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14762
+ */
14763
+ motionSliceWriter: literal("orchestrator").optional()
14746
14764
  });
14747
14765
  object({
14748
14766
  externalId: string(),
@@ -15621,109 +15639,10 @@ method(object({
15621
15639
  deviceIds: array(number()).readonly(),
15622
15640
  caps: array(string()).readonly().optional()
15623
15641
  }), record(string(), record(string(), unknown().nullable())));
15624
- /**
15625
- * Doorbell button cap. Two kinds of providers coexist behind this cap
15626
- * name (same pattern as `snapshot`):
15627
- *
15628
- * - **Native** providers: registered per-device by device-driver
15629
- * addons via `ctx.registerNativeCap` — either on a
15630
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
15631
- * or directly on the camera (Reolink registers at camera level).
15632
- * Emits an `onPressed` event every time the firmware pushes a
15633
- * ring; status tracks the last press and a pressCount since start
15634
- * (diagnostic).
15635
- *
15636
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
15637
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
15638
- * device (contact / switch / event-emitter …) into a doorbell for
15639
- * a camera. `defaultActive: false` — the operator explicitly binds
15640
- * it per camera in the device-bindings UI, then picks the source
15641
- * device + trigger in the per-device settings.
15642
- *
15643
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
15644
- * — subscribers listening at the camera level receive ring events
15645
- * with `via[]` populated. No code on the parent needed.
15646
- */
15647
- var DoorbellStatusSchema = object({
15648
- /** Ms epoch of the last press. null = never observed since this provider started. */
15649
- lastPressedAt: number().nullable(),
15650
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15651
- pressCountSinceStart: number()
15652
- });
15653
- var DoorbellPressEventSchema = object({
15654
- deviceId: number(),
15655
- timestamp: number()
15656
- });
15657
- /**
15658
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15659
- * virtual-doorbell trigger devices, exactly what the wrapper's
15660
- * `doorbellSources` persists (as `{ deviceId }` records).
15661
- */
15662
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15663
- /**
15664
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
15665
- * doorbell, owned by the `virtual-doorbell` wrapper over its
15666
- * `doorbellSources` store (D648). A source rings when one of its
15667
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
15668
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
15669
- * reports it, it never writes it.
15670
- */
15671
- var DOORBELL_SOURCE_SLOT = {
15672
- id: "doorbell-source",
15673
- label: "Doorbell trigger devices",
15674
- 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.",
15675
- shape: "association",
15676
- hostDeviceTypes: [DeviceType.Camera],
15677
- sourceCaps: SOURCE_CAPS,
15678
- cardinality: "many",
15679
- value: DoorbellSourceSlotValueSchema
15680
- };
15681
- var doorbellCapability = {
15682
- name: "doorbell",
15683
- scope: "device",
15684
- deviceNative: true,
15685
- mode: "singleton",
15686
- kind: "wrapper",
15687
- defaultActive: false,
15688
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
15689
- extensionSlots: [DOORBELL_SOURCE_SLOT],
15690
- methods: {},
15691
- events: {
15692
- /**
15693
- * Fires once per physical press. Reolink delivers via Baichuan
15694
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
15695
- * release/duration — it's a pulse.
15696
- */
15697
- onPressed: {
15698
- data: DoorbellPressEventSchema,
15699
- fromState: {
15700
- field: "lastPressedAt",
15701
- on: "advance"
15702
- }
15703
- } },
15704
- status: {
15705
- schema: DoorbellStatusSchema,
15706
- kind: "push"
15707
- },
15708
- /**
15709
- * Runtime-state slice — last press timestamp + lifetime press count.
15710
- * Mirrored by the kernel and readable via
15711
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
15712
- * without subscribing.
15713
- */
15714
- runtimeState: DoorbellStatusSchema,
15715
- /**
15716
- * 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.
15717
- *
15718
- * See `RuntimeStateDurability`. Enforced by
15719
- * `scripts/check-runtime-state-durability.ts`.
15720
- */
15721
- durability: "restored"
15722
- };
15723
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15724
- DeviceType.Camera, DeviceType.Camera;
15642
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15643
+ DeviceType.Camera;
15725
15644
  /** A slot's editable value, discriminated on `slot`. */
15726
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15645
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15727
15646
  DeviceType.Camera;
15728
15647
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15729
15648
  state: literal("unreachable"),
@@ -15760,10 +15679,11 @@ var ExtensionSlotSourceSchema = object({
15760
15679
  });
15761
15680
  /**
15762
15681
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15763
- * reported read-only, named, never written through this contract (D62). The
15764
- * virtual doorbell's sources ring only while the wrapper is bound to the
15765
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15766
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15682
+ * reported read-only, named, never written through this contract (D62) — e.g.
15683
+ * a slot whose sources act only while a wrapper is bound to the host, a
15684
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15685
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15686
+ * not be read; it is not "inactive" (D315).
15767
15687
  */
15768
15688
  var ExtensionSlotActivationSchema = object({
15769
15689
  state: _enum([
@@ -15779,7 +15699,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15779
15699
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15780
15700
  slotRef: string(),
15781
15701
  slot: ExtensionSlotIdSchema,
15782
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15702
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15783
15703
  authority: string(),
15784
15704
  activation: ExtensionSlotActivationSchema.nullable(),
15785
15705
  value: ExtensionSlotValueSchema,
@@ -16057,7 +15977,7 @@ method(object({
16057
15977
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16058
15978
  * ends in a log line, and a log line is the thing the operator asked to stop
16059
15979
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16060
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
15980
+ * 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
16061
15981
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16062
15982
  * media blackout were both diagnosed. The counters stay; this is where they can
16063
15983
  * be READ.
@@ -17433,7 +17353,7 @@ var BrokerStatusSchema$1 = _enum([
17433
17353
  "unreachable",
17434
17354
  "tls-error"
17435
17355
  ]);
17436
- var BrokerInfoSchema = object({
17356
+ var BrokerInfoSchema$1 = object({
17437
17357
  id: string(),
17438
17358
  name: string(),
17439
17359
  url: string(),
@@ -17496,7 +17416,7 @@ var StatusSchema = object({
17496
17416
  brokerCount: number(),
17497
17417
  embeddedRunning: boolean()
17498
17418
  });
17499
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17419
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17500
17420
  kind: "mutation",
17501
17421
  auth: "admin"
17502
17422
  }), method(IdInputSchema, _void(), {
@@ -19710,78 +19630,16 @@ var NcRuleInputSchema = object({
19710
19630
  */
19711
19631
  confirm: NcConfirmSchema.optional(),
19712
19632
  /**
19713
- * WAIT for face/plate recognition before saying anything.
19714
- *
19715
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
19716
- * send; the identity is neither. A face is confirmed after `confirmFrames`
19717
- * agreeing observations — p50 **11.4 s** after the track was first seen,
19718
- * measured on this hub — and an `immediate` rule enqueues on the first object
19719
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
19720
- * immediate path, and no amount of media re-resolution fixes a sentence.
19721
- *
19722
- * Only two honest answers exist, and this flag picks between them. It has
19723
- * effect ONLY on a rule that declares a recognition scope
19724
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
19725
- * other rule there is nothing to wait for and the flag is inert.
19726
- *
19727
- * | value | what happens |
19728
- * | --- | --- |
19729
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
19730
- * | 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) |
19731
- *
19732
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19733
- * on the addon cap path, and absent has to keep meaning exactly what every
19734
- * rule authored before this field meant.
19735
- *
19736
- * The cost of `true` is stated here because the editor states it too: a rule
19737
- * that waits also inherits track-close SEMANTICS — its `zones` condition
19738
- * tests every zone the track visited and a `crossing` condition can no longer
19739
- * be satisfied, because a closed track carries no crossing.
19633
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
19634
+ * seconds; the rule sends ONE message when the window closes — early, once every
19635
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
19636
+ * the rule matched, with one mosaic tile per subject.
19637
+ * Absent = plain immediate (one message per track, at the first match).
19638
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
19639
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
19640
+ * path does not run Zod defaults.
19740
19641
  */
19741
- waitForEnhancement: boolean().optional(),
19742
- /**
19743
- * GROUP a burst of subjects into ONE notification that grows.
19744
- *
19745
- * Seconds of quiet after the last matching subject before the burst is
19746
- * considered over. While it is open, the first subject enqueues immediately —
19747
- * **exactly as today, with no added latency** — and every real growth (a new
19748
- * subject, or a name confirmed on one already in it) REPLACES that
19749
- * notification with an updated one naming everybody. The push carries the
19750
- * group's own coalescing tag, so the phone replaces rather than stacks.
19751
- *
19752
- * `0` / absent = off, and off is today's behaviour byte for byte.
19753
- *
19754
- * ### Why an idle cutoff and not a window
19755
- *
19756
- * The measured seven-person arrival on device 590 spans 110 s with every
19757
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
19758
- * idle cutoff holds it as one and ends it when the arrival actually ends.
19759
- * 30 s is a widely shipped value for the same decision.
19760
- *
19761
- * ### What it replaces
19762
- *
19763
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
19764
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
19765
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
19766
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
19767
- * A group collapses the same volume by MERGING, so the cooldown becomes a
19768
- * budget over GROUPS — which is what it always meant — and a growth is never
19769
- * throttled by the window its own first member spent.
19770
- *
19771
- * ### Interaction with {@link waitForEnhancement}
19772
- *
19773
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
19774
- * TRACK CLOSE, so with both set the group is opened by the first member to
19775
- * CLOSE — already carrying its name — and grows as later members close. That
19776
- * is later, and complete. With grouping alone the group opens on the first
19777
- * object event and picks up names as they are confirmed, through the growth
19778
- * path. Neither combination fires twice for one subject.
19779
- *
19780
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19781
- * on the addon cap path, so absent must keep meaning what it meant before this
19782
- * field existed.
19783
- */
19784
- groupIdleSec: number().int().min(0).max(600).optional()
19642
+ groupingSec: number().int().min(5).max(60).optional()
19785
19643
  });
19786
19644
  /**
19787
19645
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -19829,9 +19687,10 @@ var NcRuleClearableKeySchema = _enum([
19829
19687
  "targetUsers",
19830
19688
  "snoozeOptions",
19831
19689
  "snoozeAllowGlobal",
19832
- "waitForEnhancement",
19833
19690
  "actions",
19834
19691
  "confirm",
19692
+ "groupingSec",
19693
+ "waitForEnhancement",
19835
19694
  "groupIdleSec"
19836
19695
  ]);
19837
19696
  var NcRuleUpdateInputSchema = object({
@@ -19853,9 +19712,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19853
19712
  */
19854
19713
  disabledTargetIds: array(string()).default([])
19855
19714
  });
19715
+ /**
19716
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19717
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
19718
+ * job is not an open state, and the alarm stays instant.
19719
+ */
19720
+ var NcStateSummarySectionIdSchema = _enum([
19721
+ "device-state",
19722
+ "streams",
19723
+ "battery",
19724
+ "consumables",
19725
+ "tanks",
19726
+ "detection-blind",
19727
+ "nodes",
19728
+ "addons",
19729
+ "updates"
19730
+ ]);
19856
19731
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
19857
19732
  var NcStateSummaryPreviewSectionSchema = object({
19858
- id: string(),
19733
+ id: NcStateSummarySectionIdSchema,
19859
19734
  status: _enum(["read", "unavailable"]),
19860
19735
  items: number().int().nonnegative(),
19861
19736
  reason: string().optional()
@@ -19865,7 +19740,7 @@ var NcStateSummaryPreviewSectionSchema = object({
19865
19740
  * a `rule` split (no `section`), one section's on a `section` split.
19866
19741
  */
19867
19742
  var NcStateSummaryPreviewRowSchema = object({
19868
- section: string().optional(),
19743
+ section: NcStateSummarySectionIdSchema.optional(),
19869
19744
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19870
19745
  title: string(),
19871
19746
  text: string(),
@@ -20302,6 +20177,29 @@ object({
20302
20177
  firstAt: number(),
20303
20178
  lastAt: number()
20304
20179
  });
20180
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20181
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20182
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20183
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20184
+ var NcAlarmModeDelaysListSchema = array(object({
20185
+ mode: AlarmArmModeSchema,
20186
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20187
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20188
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20189
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20190
+ var NcAlarmModeDelaysEditListSchema = array(object({
20191
+ mode: AlarmArmModeSchema,
20192
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20193
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20194
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20195
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20196
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20197
+ var NcAlarmNonBlockingEditSchema = object({
20198
+ mode: AlarmArmModeSchema,
20199
+ deviceId: number().int().positive(),
20200
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20201
+ nonBlocking: boolean()
20202
+ });
20305
20203
  /**
20306
20204
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20307
20205
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20310,10 +20208,10 @@ object({
20310
20208
  var NcAlarmNonBlockingListSchema = array(object({
20311
20209
  mode: AlarmArmModeSchema,
20312
20210
  deviceIds: array(number().int()).max(200)
20313
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20211
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20314
20212
  /**
20315
- * The three durations the panel's state machine runs on, who hears about its
20316
- * transitions, and which openings each mode tolerates.
20213
+ * The three durations — global, and per mode since D697 — the panel's state
20214
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20317
20215
  *
20318
20216
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20319
20217
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20323,15 +20221,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20323
20221
  */
20324
20222
  var NcAlarmSettingsSchema = object({
20325
20223
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20326
- exitDelaySec: number().int().min(0).max(600),
20224
+ exitDelaySec: NcAlarmDelaySecSchema,
20327
20225
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20328
- entryDelaySec: number().int().min(0).max(600),
20226
+ entryDelaySec: NcAlarmDelaySecSchema,
20329
20227
  /**
20330
20228
  * How long `triggered` lasts before the panel re-arms itself.
20331
20229
  * **0 = until an operator disarms it** — the behaviour before this field
20332
20230
  * existed, and therefore what an untouched install keeps doing.
20333
20231
  */
20334
- triggeredDurationSec: number().int().min(0).max(3600),
20232
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20335
20233
  /**
20336
20234
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20337
20235
  * remove after one release. Optional so an older admin's patch (which still
@@ -20354,17 +20252,30 @@ var NcAlarmSettingsSchema = object({
20354
20252
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20355
20253
  * parses as "every opening blocks" — the behaviour it was written under.
20356
20254
  */
20357
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20255
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20256
+ /**
20257
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20258
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20259
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20260
+ */
20261
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20358
20262
  });
20359
20263
  /**
20360
20264
  * Every field optional — a tab edits one control at a time.
20361
20265
  *
20362
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20363
- * remove an inner `.default()`, so a patch that never named the field would
20364
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20365
- * (the same trap {@link NcRulePatchSchema} documents).
20266
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20267
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20268
+ * named the field would parse to `[]` and wipe every mode's list on an
20269
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20270
+ * `modeDelays` means EDITS, not the stored overrides.
20366
20271
  */
20367
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20272
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20273
+ nonBlocking: NcAlarmNonBlockingListSchema,
20274
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20275
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20276
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20277
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20278
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20368
20279
  /**
20369
20280
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20370
20281
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20464,6 +20375,28 @@ var NcAlarmConfigSchema = object({
20464
20375
  */
20465
20376
  live: NcAlarmLiveSchema.optional()
20466
20377
  });
20378
+ var NcAlarmSensorReadingSchema = _enum([
20379
+ "open",
20380
+ "closed",
20381
+ "unknown",
20382
+ "not-opening"
20383
+ ]);
20384
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20385
+ var NcAlarmSensorStateSchema = object({
20386
+ deviceId: number().int().positive(),
20387
+ reading: NcAlarmSensorReadingSchema,
20388
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20389
+ state: string().nullable(),
20390
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20391
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20392
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20393
+ online: boolean().nullable()
20394
+ });
20395
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20396
+ var NcAlarmSensorsSchema = object({
20397
+ sensors: array(NcAlarmSensorStateSchema),
20398
+ readAt: number().int().nonnegative()
20399
+ });
20467
20400
  /**
20468
20401
  * ONE rule's demand on ONE camera's clip ring.
20469
20402
  *
@@ -20554,7 +20487,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20554
20487
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20555
20488
  kind: "mutation",
20556
20489
  auth: "admin"
20557
- });
20490
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20558
20491
  /**
20559
20492
  * Zod schemas for persisted record types.
20560
20493
  *
@@ -20901,12 +20834,26 @@ var CameraSensorRefSchema = object({
20901
20834
  function cameraSensorRefKey(ref) {
20902
20835
  return `${ref.addonId}/${ref.stableId}`;
20903
20836
  }
20904
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20905
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20906
- var CameraSensorsConfigSchema = object({
20907
- mode: CameraSensorsModeSchema,
20908
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20909
- }).superRefine((value, ctx) => {
20837
+ /**
20838
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20839
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20840
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20841
+ * camera's own motion counts only while a confirm sensor is active — with or
20842
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20843
+ */
20844
+ var CameraSensorModeSchema = _enum([
20845
+ "in-addition",
20846
+ "confirm",
20847
+ "replace"
20848
+ ]);
20849
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20850
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20851
+ /**
20852
+ * A camera's attached sensors. A CS-1 row carried an envelope
20853
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20854
+ * what the write stores (D672 rule 3), so it is never written again.
20855
+ */
20856
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20910
20857
  const seen = /* @__PURE__ */ new Set();
20911
20858
  value.sensors.forEach((ref, index) => {
20912
20859
  const key = cameraSensorRefKey(ref);
@@ -20918,39 +20865,41 @@ var CameraSensorsConfigSchema = object({
20918
20865
  seen.add(key);
20919
20866
  });
20920
20867
  });
20921
- var RefFields = {
20868
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20869
+ var AttachmentFields = {
20922
20870
  addonId: string(),
20923
- stableId: string()
20871
+ stableId: string(),
20872
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20924
20873
  };
20925
20874
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20926
20875
  object({
20927
- ...RefFields,
20876
+ ...AttachmentFields,
20928
20877
  state: literal("ready"),
20929
20878
  deviceId: number(),
20930
20879
  name: string(),
20931
20880
  caps: array(string()).readonly()
20932
20881
  }),
20933
20882
  object({
20934
- ...RefFields,
20883
+ ...AttachmentFields,
20935
20884
  state: literal("offline"),
20936
20885
  deviceId: number(),
20937
20886
  name: string(),
20938
20887
  reason: _enum(["offline", "disabled"])
20939
20888
  }),
20940
20889
  object({
20941
- ...RefFields,
20890
+ ...AttachmentFields,
20942
20891
  state: literal("missing"),
20943
20892
  reason: string()
20944
20893
  }),
20945
20894
  object({
20946
- ...RefFields,
20895
+ ...AttachmentFields,
20947
20896
  state: literal("unsupported"),
20948
20897
  deviceId: number(),
20949
20898
  name: string(),
20950
20899
  reason: string()
20951
20900
  }),
20952
20901
  object({
20953
- ...RefFields,
20902
+ ...AttachmentFields,
20954
20903
  state: literal("unreadable"),
20955
20904
  reason: string()
20956
20905
  })
@@ -20963,17 +20912,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20963
20912
  * say.
20964
20913
  */
20965
20914
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20915
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20916
+ var CameraOwnMotionSchema = _enum([
20917
+ "always",
20918
+ "when-confirmed",
20919
+ "never"
20920
+ ]);
20921
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20922
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20923
+ /**
20924
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20925
+ * never the effective value. The camera's `motion` slice is the effective one,
20926
+ * so a view of the camera's own row reads this.
20927
+ * - `atMs`: when the bridge received the camera's last own edge.
20928
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20929
+ * AND it is younger than the window the bridge counts the camera's own motion
20930
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20931
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20932
+ * within the window; a status read is a snapshot, so a live view re-asks.
20933
+ * Absent = this orchestrator has not received the camera's own motion since it
20934
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20935
+ */
20936
+ var CameraRawLevelSchema = object({
20937
+ detected: boolean(),
20938
+ atMs: number()
20939
+ });
20966
20940
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
20967
- object({ state: literal("not-configured") }),
20941
+ object({
20942
+ state: literal("not-configured"),
20943
+ cameraLevel: CameraRawLevelSchema.optional()
20944
+ }),
20968
20945
  object({
20969
20946
  state: literal("unreadable"),
20970
- reason: string()
20947
+ reason: string(),
20948
+ cameraLevel: CameraRawLevelSchema.optional()
20971
20949
  }),
20972
20950
  object({
20973
20951
  state: literal("configured"),
20974
- mode: CameraSensorsModeSchema,
20952
+ cameraLevel: CameraRawLevelSchema.optional(),
20975
20953
  sensors: array(CameraSensorAttachmentSchema).readonly(),
20976
- notForwarded: CameraSensorsNotForwardedSchema.optional()
20954
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
20955
+ cameraMotion: CameraOwnMotionSchema.optional(),
20956
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
20957
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
20977
20958
  })
20978
20959
  ]);
20979
20960
  Object.freeze({
@@ -21658,14 +21639,14 @@ var TrackSchema = object({
21658
21639
  * `derive-returned-null tile=standin`,
21659
21640
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
21660
21641
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
21661
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
21642
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
21662
21643
  * tile is a face/plate stand-in, a raster crop, or an icon.
21663
21644
  *
21664
21645
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
21665
21646
  * the TILE ranked below native, so a track whose thumbnail landed natively
21666
21647
  * while its key frame missed carried no reason at all — three of the four
21667
21648
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
21668
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
21649
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
21669
21650
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
21670
21651
  * lastFrame copy source`), so its absence is now on this line whatever the
21671
21652
  * tile ended up being.
@@ -21752,7 +21733,7 @@ var MotionEventSchema = object({
21752
21733
  /**
21753
21734
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
21754
21735
  * first entry is always `0`) of every genuine off→on transition the
21755
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
21736
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
21756
21737
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
21757
21738
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
21758
21739
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -22276,6 +22257,7 @@ var KeyEventSchema = object({
22276
22257
  bestEventId: string(),
22277
22258
  /** Track lifetime in ms (lastSeen - firstSeen). */
22278
22259
  windowMs: number().optional(),
22260
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
22279
22261
  ...TrackFlagFields,
22280
22262
  ...TrackRetrainFields
22281
22263
  });
@@ -24204,8 +24186,10 @@ var RunnerCameraConfigSchema = object({
24204
24186
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24205
24187
  * analyzer providers) running on decoded frames in this runner.
24206
24188
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24207
- * analytics). The provider emits ProviderMotion
24208
- * events; the orchestrator forwards to `reportMotion`.
24189
+ * analytics). The provider emits its raw push as `ProviderMotion`
24190
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24191
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24192
+ * `reportMotion`.
24209
24193
  */
24210
24194
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24211
24195
  /**
@@ -24382,7 +24366,15 @@ var RunnerLocalLoadSchema = object({
24382
24366
  hasGpu: boolean(),
24383
24367
  inferenceBackend: string().optional(),
24384
24368
  cpuCores: number().optional()
24385
- })
24369
+ }),
24370
+ /**
24371
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24372
+ * runner never writes it. ABSENT = a runner older than D696, which still
24373
+ * writes the slice from its phase machine; the orchestrator does not write
24374
+ * while any runner node is absent-or-unanswered, so one slice never has two
24375
+ * writers.
24376
+ */
24377
+ motionSliceWriter: literal("orchestrator").optional()
24386
24378
  });
24387
24379
  /**
24388
24380
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -27151,7 +27143,7 @@ var ClipPlaybackSchema = object({
27151
27143
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
27152
27144
  * time the camera is awake for its own reasons — is deliberately not a member:
27153
27145
  * it was proposed, it is free on the battery, and the operator declined it on
27154
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
27146
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
27155
27147
  * D558 "Considered and not taken").
27156
27148
  */
27157
27149
  var ClipWakeSchema = _enum(["authorised"]);
@@ -27412,7 +27404,7 @@ DeviceType.Camera, method(object({
27412
27404
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
27413
27405
  * assumed the answer was a fan-out over everything a camera has. The
27414
27406
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
27415
- * solo"* — so the list is asked of one provider at a time and there is
27407
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
27416
27408
  * nothing to filter out of it.
27417
27409
  */
27418
27410
  provider: string().min(1)
@@ -30015,6 +30007,70 @@ onStatusChanged: { data: object({
30015
30007
  * whether persisting is worth a SQLite commit. */
30016
30008
  volatileStateFields: ["lastChangedAt"]
30017
30009
  };
30010
+ var DoorbellStatusSchema = object({
30011
+ /** Ms epoch of the last press. null = never observed since this provider started. */
30012
+ lastPressedAt: number().nullable(),
30013
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
30014
+ pressCountSinceStart: number()
30015
+ });
30016
+ var DoorbellPressEventSchema = object({
30017
+ deviceId: number(),
30018
+ timestamp: number()
30019
+ });
30020
+ /**
30021
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
30022
+ * they are the same cap:
30023
+ *
30024
+ * - **Native** providers, registered per device by a driver addon through
30025
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
30026
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
30027
+ * camera level). They emit `onPressed` on every firmware ring.
30028
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
30029
+ * the cap, its `lastPressedAt` rising from the sources the operator
30030
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
30031
+ * from that field's advance (`fromState`).
30032
+ *
30033
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
30034
+ */
30035
+ var doorbellCapability = {
30036
+ name: "doorbell",
30037
+ scope: "device",
30038
+ deviceNative: true,
30039
+ mode: "singleton",
30040
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
30041
+ methods: {},
30042
+ events: {
30043
+ /**
30044
+ * Fires once per physical press. Reolink delivers via Baichuan
30045
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
30046
+ * release/duration — it's a pulse.
30047
+ */
30048
+ onPressed: {
30049
+ data: DoorbellPressEventSchema,
30050
+ fromState: {
30051
+ field: "lastPressedAt",
30052
+ on: "advance"
30053
+ }
30054
+ } },
30055
+ status: {
30056
+ schema: DoorbellStatusSchema,
30057
+ kind: "push"
30058
+ },
30059
+ /**
30060
+ * Runtime-state slice — last press timestamp + lifetime press count.
30061
+ * Mirrored by the kernel and readable via
30062
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
30063
+ * without subscribing.
30064
+ */
30065
+ runtimeState: DoorbellStatusSchema,
30066
+ /**
30067
+ * 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.
30068
+ *
30069
+ * See `RuntimeStateDurability`. Enforced by
30070
+ * `scripts/check-runtime-state-durability.ts`.
30071
+ */
30072
+ durability: "restored"
30073
+ };
30018
30074
  /**
30019
30075
  * Enum-state sensor — a string value picked from a finite option set.
30020
30076
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -32159,9 +32215,9 @@ var MotionStatusSchema = object({
32159
32215
  /** Ms epoch of the last detected-true observation. Null if never detected. */
32160
32216
  lastDetectedAt: number().nullable(),
32161
32217
  /**
32162
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
32163
- * `null` while false and on every `Sensor` device (D475) — see that
32164
- * constant's doc for the one-authority rule.
32218
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
32219
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
32220
+ * device (D475) — see that constant's doc for the one-authority rule.
32165
32221
  *
32166
32222
  * ## Reading this field still arms nothing
32167
32223
  *
@@ -32179,34 +32235,31 @@ var MotionStatusSchema = object({
32179
32235
  * `addon-export-alexa/src/motion-clear-hold.ts` and
32180
32236
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
32181
32237
  *
32182
- * ## Who writes it
32183
- *
32184
- * - **Cameras** — the runner's phase machine, `active → watching` on
32185
- * `cooldown_expired`, which then writes this slice with
32186
- * `detected: false` (`handlePhaseChanged` in
32187
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
32188
- * matters most for the sources that only ever push a rising one:
32189
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
32190
- * a false.
32191
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
32192
- * provider pushes the false itself, from the upstream system's own
32193
- * state change. No phase machine is involved.
32194
- *
32195
- * ### The phase machine is CANONICAL, not sole — and that is a defect
32196
- *
32197
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
32198
- * phase machine is the sole writer for a camera. It is not.
32199
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
32200
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
32201
- * Hikvision's comment says why: it read THIS docblock, agreed the
32202
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
32203
- * two authorities can disagree about one slice, which this repo
32204
- * forbids, and the doc said otherwise — which is worse than saying
32205
- * nothing, because it reads as verification.
32206
- *
32207
- * This predates D475 and is not fixed there: the fix touches every
32208
- * camera provider. Recorded in D475's Consequences. Do not restore the
32209
- * "sole writer" wording without also removing the other writers.
32238
+ * ## Who writes it (D696)
32239
+ *
32240
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
32241
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
32242
+ * `camera-sensors/motion-slice.ts`), alongside the effective
32243
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
32244
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
32245
+ * device activity, as the camera's `motionSources` counts them. A source
32246
+ * that never sends a clear falls one window after its last `true`.
32247
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
32248
+ * writes this slice (not even a boot seed), and neither does the runner's
32249
+ * phase machine: its phase is "a session is attached" for every on-motion
32250
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
32251
+ * A provider's `isDetected` answers from the hub's slice.
32252
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32253
+ * imports) — the provider pushes both edges itself, from the upstream
32254
+ * system's own state change. That is the sensor's own fact.
32255
+ *
32256
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
32257
+ * `motion` slice; each sensor writer is a named exemption.
32258
+ *
32259
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
32260
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
32261
+ * it, every provider seeded it at boot, and every session left it
32262
+ * `detected: true` after its detach.
32210
32263
  */
32211
32264
  autoClearAfterMs: number().nullable()
32212
32265
  });
@@ -32278,11 +32331,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
32278
32331
  */
32279
32332
  runtimeState: MotionStatusSchema,
32280
32333
  /**
32281
- * Runtime-state durability: **session** — every writer of this slice
32334
+ * Runtime-state durability: **session** — the writer of this slice
32282
32335
  * writes only on an EDGE, so a restored `detected: true` would stay
32283
32336
  * frozen until the next one instead of being corrected. The next edge
32284
- * re-publishes the real state. (On who the writers are, and why there
32285
- * is more than one, see `autoClearAfterMs` above.)
32337
+ * re-publishes the real state, and the orchestrator re-publishes every
32338
+ * camera when it starts writing (D696; on who writes it, see
32339
+ * `autoClearAfterMs` above).
32286
32340
  *
32287
32341
  * See `RuntimeStateDurability`. Enforced by
32288
32342
  * `scripts/check-runtime-state-durability.ts`.
@@ -34665,8 +34719,7 @@ var ptzAutotrackCapability = {
34665
34719
  deviceNative: true,
34666
34720
  mode: "singleton",
34667
34721
  /**
34668
- * Two kinds of provider behind one name, the same shape `snapshot` and
34669
- * `doorbell` use:
34722
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
34670
34723
  *
34671
34724
  * - **Native**: the camera's own firmware autotrack, registered per device by
34672
34725
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -34674,7 +34727,7 @@ var ptzAutotrackCapability = {
34674
34727
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
34675
34728
  * which follows a subject with `ptz.move` pulses driven by the detection
34676
34729
  * pipeline. `defaultActive: false` — the operator binds it per camera in
34677
- * the bindings UI, exactly as `virtual-doorbell` is bound.
34730
+ * the bindings UI.
34678
34731
  *
34679
34732
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
34680
34733
  * one switch for the function either way. A camera never has both driving its
@@ -35349,7 +35402,7 @@ var ReadGopBytesResultSchema = object({
35349
35402
  /**
35350
35403
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
35351
35404
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
35352
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
35405
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
35353
35406
  * a replay needs several seconds of native pixels, not one frame.
35354
35407
  *
35355
35408
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -38713,6 +38766,7 @@ var zoneRulesCapability = {
38713
38766
  */
38714
38767
  durability: "restored"
38715
38768
  };
38769
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
38716
38770
  /**
38717
38771
  * Accessory device helpers — shared across drivers.
38718
38772
  *
@@ -39772,13 +39826,14 @@ var BaseDeviceProvider = class extends BaseAddon {
39772
39826
  async getStatus() {
39773
39827
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
39774
39828
  const summary = this.restoreFailureSummary();
39775
- if (summary === null) return {
39829
+ const base = {
39776
39830
  connected: true,
39777
- deviceCount: all.length
39831
+ deviceCount: all.length,
39832
+ motionSliceWriter: "orchestrator"
39778
39833
  };
39834
+ if (summary === null) return base;
39779
39835
  return {
39780
- connected: true,
39781
- deviceCount: all.length,
39836
+ ...base,
39782
39837
  error: summary
39783
39838
  };
39784
39839
  }
@@ -45280,6 +45335,12 @@ Object.freeze({
45280
45335
  addonId: null,
45281
45336
  access: "view"
45282
45337
  },
45338
+ "notificationRules.getAlarmSensors": {
45339
+ capName: "notification-rules",
45340
+ capScope: "system",
45341
+ addonId: null,
45342
+ access: "view"
45343
+ },
45283
45344
  "notificationRules.getClipRetentionAsks": {
45284
45345
  capName: "notification-rules",
45285
45346
  capScope: "system",
@@ -48858,6 +48919,11 @@ Object.freeze({
48858
48919
  }
48859
48920
  });
48860
48921
  Object.freeze({
48922
+ "accessories.getStatus": [{
48923
+ name: "deviceId",
48924
+ form: "single",
48925
+ optional: false
48926
+ }],
48861
48927
  "accessories.setChildHidden": [{
48862
48928
  name: "childDeviceId",
48863
48929
  form: "single",
@@ -48877,6 +48943,11 @@ Object.freeze({
48877
48943
  form: "single",
48878
48944
  optional: false
48879
48945
  }],
48946
+ "airQualitySensor.getStatus": [{
48947
+ name: "deviceId",
48948
+ form: "single",
48949
+ optional: false
48950
+ }],
48880
48951
  "alarmPanel.arm": [{
48881
48952
  name: "deviceId",
48882
48953
  form: "single",
@@ -48887,11 +48958,36 @@ Object.freeze({
48887
48958
  form: "single",
48888
48959
  optional: false
48889
48960
  }],
48961
+ "alarmPanel.getStatus": [{
48962
+ name: "deviceId",
48963
+ form: "single",
48964
+ optional: false
48965
+ }],
48890
48966
  "alarmPanel.trigger": [{
48891
48967
  name: "deviceId",
48892
48968
  form: "single",
48893
48969
  optional: false
48894
48970
  }],
48971
+ "ambientLightSensor.getStatus": [{
48972
+ name: "deviceId",
48973
+ form: "single",
48974
+ optional: false
48975
+ }],
48976
+ "audioAnalysis.applyDeviceSettingsPatch": [{
48977
+ name: "deviceId",
48978
+ form: "single",
48979
+ optional: false
48980
+ }],
48981
+ "audioAnalysis.getDeviceLiveContribution": [{
48982
+ name: "deviceId",
48983
+ form: "single",
48984
+ optional: false
48985
+ }],
48986
+ "audioAnalysis.getDeviceSettingsContribution": [{
48987
+ name: "deviceId",
48988
+ form: "single",
48989
+ optional: false
48990
+ }],
48895
48991
  "audioAnalysis.resolveDeviceSettings": [{
48896
48992
  name: "deviceId",
48897
48993
  form: "single",
@@ -48932,16 +49028,36 @@ Object.freeze({
48932
49028
  form: "single",
48933
49029
  optional: false
48934
49030
  }],
49031
+ "automationControl.getStatus": [{
49032
+ name: "deviceId",
49033
+ form: "single",
49034
+ optional: false
49035
+ }],
48935
49036
  "automationControl.trigger": [{
48936
49037
  name: "deviceId",
48937
49038
  form: "single",
48938
49039
  optional: false
48939
49040
  }],
49041
+ "battery.getStatus": [{
49042
+ name: "deviceId",
49043
+ form: "single",
49044
+ optional: false
49045
+ }],
48940
49046
  "battery.wakeForStream": [{
48941
49047
  name: "deviceId",
48942
49048
  form: "single",
48943
49049
  optional: false
48944
49050
  }],
49051
+ "binary.getStatus": [{
49052
+ name: "deviceId",
49053
+ form: "single",
49054
+ optional: false
49055
+ }],
49056
+ "brightness.getStatus": [{
49057
+ name: "deviceId",
49058
+ form: "single",
49059
+ optional: false
49060
+ }],
48945
49061
  "brightness.setBrightness": [{
48946
49062
  name: "deviceId",
48947
49063
  form: "single",
@@ -48957,6 +49073,26 @@ Object.freeze({
48957
49073
  form: "single",
48958
49074
  optional: false
48959
49075
  }],
49076
+ "cameraCredentials.getStatus": [{
49077
+ name: "deviceId",
49078
+ form: "single",
49079
+ optional: false
49080
+ }],
49081
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
49082
+ name: "deviceId",
49083
+ form: "single",
49084
+ optional: false
49085
+ }],
49086
+ "cameraGridLayout.getDeviceLiveContribution": [{
49087
+ name: "deviceId",
49088
+ form: "single",
49089
+ optional: false
49090
+ }],
49091
+ "cameraGridLayout.getDeviceSettingsContribution": [{
49092
+ name: "deviceId",
49093
+ form: "single",
49094
+ optional: false
49095
+ }],
48960
49096
  "cameraGridLayout.getLayout": [{
48961
49097
  name: "deviceId",
48962
49098
  form: "single",
@@ -48972,6 +49108,21 @@ Object.freeze({
48972
49108
  form: "single",
48973
49109
  optional: false
48974
49110
  }],
49111
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
49112
+ name: "deviceId",
49113
+ form: "single",
49114
+ optional: false
49115
+ }],
49116
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
49117
+ name: "deviceId",
49118
+ form: "single",
49119
+ optional: false
49120
+ }],
49121
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
49122
+ name: "deviceId",
49123
+ form: "single",
49124
+ optional: false
49125
+ }],
48975
49126
  "cameraStreams.getBrokerStreams": [{
48976
49127
  name: "deviceId",
48977
49128
  form: "single",
@@ -48997,6 +49148,16 @@ Object.freeze({
48997
49148
  form: "single",
48998
49149
  optional: false
48999
49150
  }],
49151
+ "carbonMonoxide.getStatus": [{
49152
+ name: "deviceId",
49153
+ form: "single",
49154
+ optional: false
49155
+ }],
49156
+ "climateControl.getStatus": [{
49157
+ name: "deviceId",
49158
+ form: "single",
49159
+ optional: false
49160
+ }],
49000
49161
  "climateControl.setFanMode": [{
49001
49162
  name: "deviceId",
49002
49163
  form: "single",
@@ -49037,16 +49198,41 @@ Object.freeze({
49037
49198
  form: "single",
49038
49199
  optional: false
49039
49200
  }],
49201
+ "color.getStatus": [{
49202
+ name: "deviceId",
49203
+ form: "single",
49204
+ optional: false
49205
+ }],
49040
49206
  "color.setColor": [{
49041
49207
  name: "deviceId",
49042
49208
  form: "single",
49043
49209
  optional: false
49044
49210
  }],
49211
+ "connectivity.getStatus": [{
49212
+ name: "deviceId",
49213
+ form: "single",
49214
+ optional: false
49215
+ }],
49216
+ "consumables.getStatus": [{
49217
+ name: "deviceId",
49218
+ form: "single",
49219
+ optional: false
49220
+ }],
49045
49221
  "consumables.reset": [{
49046
49222
  name: "deviceId",
49047
49223
  form: "single",
49048
49224
  optional: false
49049
49225
  }],
49226
+ "contact.getStatus": [{
49227
+ name: "deviceId",
49228
+ form: "single",
49229
+ optional: false
49230
+ }],
49231
+ "control.getStatus": [{
49232
+ name: "deviceId",
49233
+ form: "single",
49234
+ optional: false
49235
+ }],
49050
49236
  "control.setValue": [{
49051
49237
  name: "deviceId",
49052
49238
  form: "single",
@@ -49057,6 +49243,11 @@ Object.freeze({
49057
49243
  form: "single",
49058
49244
  optional: false
49059
49245
  }],
49246
+ "cover.getStatus": [{
49247
+ name: "deviceId",
49248
+ form: "single",
49249
+ optional: false
49250
+ }],
49060
49251
  "cover.open": [{
49061
49252
  name: "deviceId",
49062
49253
  form: "single",
@@ -49082,6 +49273,11 @@ Object.freeze({
49082
49273
  form: "single",
49083
49274
  optional: false
49084
49275
  }],
49276
+ "dayNight.getStatus": [{
49277
+ name: "deviceId",
49278
+ form: "single",
49279
+ optional: false
49280
+ }],
49085
49281
  "dayNight.setSettings": [{
49086
49282
  name: "deviceId",
49087
49283
  form: "single",
@@ -49092,11 +49288,31 @@ Object.freeze({
49092
49288
  form: "single",
49093
49289
  optional: true
49094
49290
  }],
49291
+ "detectionPipeline.applyDeviceSettingsPatch": [{
49292
+ name: "deviceId",
49293
+ form: "single",
49294
+ optional: false
49295
+ }],
49296
+ "detectionPipeline.getDeviceLiveContribution": [{
49297
+ name: "deviceId",
49298
+ form: "single",
49299
+ optional: false
49300
+ }],
49301
+ "detectionPipeline.getDeviceSettingsContribution": [{
49302
+ name: "deviceId",
49303
+ form: "single",
49304
+ optional: false
49305
+ }],
49095
49306
  "deviceAdminLink.getAdminLink": [{
49096
49307
  name: "deviceId",
49097
49308
  form: "single",
49098
49309
  optional: false
49099
49310
  }],
49311
+ "deviceAdoption.getStatus": [{
49312
+ name: "deviceId",
49313
+ form: "single",
49314
+ optional: false
49315
+ }],
49100
49316
  "deviceAdoption.release": [{
49101
49317
  name: "camDeviceId",
49102
49318
  form: "single",
@@ -49112,6 +49328,11 @@ Object.freeze({
49112
49328
  form: "single",
49113
49329
  optional: false
49114
49330
  }],
49331
+ "deviceDiscovery.getStatus": [{
49332
+ name: "deviceId",
49333
+ form: "single",
49334
+ optional: false
49335
+ }],
49115
49336
  "deviceDiscovery.listDiscovered": [{
49116
49337
  name: "deviceId",
49117
49338
  form: "single",
@@ -49131,6 +49352,21 @@ Object.freeze({
49131
49352
  form: "single",
49132
49353
  optional: false
49133
49354
  }],
49355
+ "deviceExport.applyDeviceSettingsPatch": [{
49356
+ name: "deviceId",
49357
+ form: "single",
49358
+ optional: false
49359
+ }],
49360
+ "deviceExport.getDeviceLiveContribution": [{
49361
+ name: "deviceId",
49362
+ form: "single",
49363
+ optional: false
49364
+ }],
49365
+ "deviceExport.getDeviceSettingsContribution": [{
49366
+ name: "deviceId",
49367
+ form: "single",
49368
+ optional: false
49369
+ }],
49134
49370
  "deviceExtension.listCandidates": [{
49135
49371
  name: "deviceId",
49136
49372
  form: "single",
@@ -49479,6 +49715,26 @@ Object.freeze({
49479
49715
  form: "single",
49480
49716
  optional: false
49481
49717
  }],
49718
+ "deviceStatus.getStatus": [{
49719
+ name: "deviceId",
49720
+ form: "single",
49721
+ optional: false
49722
+ }],
49723
+ "doorbell.getStatus": [{
49724
+ name: "deviceId",
49725
+ form: "single",
49726
+ optional: false
49727
+ }],
49728
+ "enumSensor.getStatus": [{
49729
+ name: "deviceId",
49730
+ form: "single",
49731
+ optional: false
49732
+ }],
49733
+ "eventEmitter.getStatus": [{
49734
+ name: "deviceId",
49735
+ form: "single",
49736
+ optional: false
49737
+ }],
49482
49738
  "faceGallery.getFaceByTrack": [{
49483
49739
  name: "deviceId",
49484
49740
  form: "single",
@@ -49493,6 +49749,11 @@ Object.freeze({
49493
49749
  form: "array",
49494
49750
  optional: true
49495
49751
  }],
49752
+ "fanControl.getStatus": [{
49753
+ name: "deviceId",
49754
+ form: "single",
49755
+ optional: false
49756
+ }],
49496
49757
  "fanControl.setDirection": [{
49497
49758
  name: "deviceId",
49498
49759
  form: "single",
@@ -49513,6 +49774,26 @@ Object.freeze({
49513
49774
  form: "single",
49514
49775
  optional: false
49515
49776
  }],
49777
+ "featureProbe.getStatus": [{
49778
+ name: "deviceId",
49779
+ form: "single",
49780
+ optional: false
49781
+ }],
49782
+ "flood.getStatus": [{
49783
+ name: "deviceId",
49784
+ form: "single",
49785
+ optional: false
49786
+ }],
49787
+ "gas.getStatus": [{
49788
+ name: "deviceId",
49789
+ form: "single",
49790
+ optional: false
49791
+ }],
49792
+ "humidifier.getStatus": [{
49793
+ name: "deviceId",
49794
+ form: "single",
49795
+ optional: false
49796
+ }],
49516
49797
  "humidifier.setMode": [{
49517
49798
  name: "deviceId",
49518
49799
  form: "single",
@@ -49528,11 +49809,26 @@ Object.freeze({
49528
49809
  form: "single",
49529
49810
  optional: false
49530
49811
  }],
49812
+ "humiditySensor.getStatus": [{
49813
+ name: "deviceId",
49814
+ form: "single",
49815
+ optional: false
49816
+ }],
49817
+ "image.getStatus": [{
49818
+ name: "deviceId",
49819
+ form: "single",
49820
+ optional: false
49821
+ }],
49531
49822
  "imageSettings.getOptions": [{
49532
49823
  name: "deviceId",
49533
49824
  form: "single",
49534
49825
  optional: false
49535
49826
  }],
49827
+ "imageSettings.getStatus": [{
49828
+ name: "deviceId",
49829
+ form: "single",
49830
+ optional: false
49831
+ }],
49536
49832
  "imageSettings.setSettings": [{
49537
49833
  name: "deviceId",
49538
49834
  form: "single",
@@ -49543,6 +49839,11 @@ Object.freeze({
49543
49839
  form: "single",
49544
49840
  optional: false
49545
49841
  }],
49842
+ "intercom.getStatus": [{
49843
+ name: "deviceId",
49844
+ form: "single",
49845
+ optional: false
49846
+ }],
49546
49847
  "intercom.handleAnswer": [{
49547
49848
  name: "deviceId",
49548
49849
  form: "single",
@@ -49573,6 +49874,11 @@ Object.freeze({
49573
49874
  form: "single",
49574
49875
  optional: false
49575
49876
  }],
49877
+ "lawnMowerControl.getStatus": [{
49878
+ name: "deviceId",
49879
+ form: "single",
49880
+ optional: false
49881
+ }],
49576
49882
  "lawnMowerControl.pause": [{
49577
49883
  name: "deviceId",
49578
49884
  form: "single",
@@ -49583,6 +49889,11 @@ Object.freeze({
49583
49889
  form: "single",
49584
49890
  optional: false
49585
49891
  }],
49892
+ "lockControl.getStatus": [{
49893
+ name: "deviceId",
49894
+ form: "single",
49895
+ optional: false
49896
+ }],
49586
49897
  "lockControl.lock": [{
49587
49898
  name: "deviceId",
49588
49899
  form: "single",
@@ -49598,6 +49909,11 @@ Object.freeze({
49598
49909
  form: "single",
49599
49910
  optional: false
49600
49911
  }],
49912
+ "mediaPlayer.getStatus": [{
49913
+ name: "deviceId",
49914
+ form: "single",
49915
+ optional: false
49916
+ }],
49601
49917
  "mediaPlayer.next": [{
49602
49918
  name: "deviceId",
49603
49919
  form: "single",
@@ -49658,6 +49974,11 @@ Object.freeze({
49658
49974
  form: "single",
49659
49975
  optional: false
49660
49976
  }],
49977
+ "motion.getStatus": [{
49978
+ name: "deviceId",
49979
+ form: "single",
49980
+ optional: false
49981
+ }],
49661
49982
  "motion.isDetected": [{
49662
49983
  name: "deviceId",
49663
49984
  form: "single",
@@ -49668,11 +49989,31 @@ Object.freeze({
49668
49989
  form: "single",
49669
49990
  optional: false
49670
49991
  }],
49992
+ "motionDetection.applyDeviceSettingsPatch": [{
49993
+ name: "deviceId",
49994
+ form: "single",
49995
+ optional: false
49996
+ }],
49997
+ "motionDetection.getDeviceLiveContribution": [{
49998
+ name: "deviceId",
49999
+ form: "single",
50000
+ optional: false
50001
+ }],
50002
+ "motionDetection.getDeviceSettingsContribution": [{
50003
+ name: "deviceId",
50004
+ form: "single",
50005
+ optional: false
50006
+ }],
49671
50007
  "motionDetection.removeCamera": [{
49672
50008
  name: "deviceId",
49673
50009
  form: "single",
49674
50010
  optional: false
49675
50011
  }],
50012
+ "motionTrigger.getStatus": [{
50013
+ name: "deviceId",
50014
+ form: "single",
50015
+ optional: false
50016
+ }],
49676
50017
  "motionTrigger.setMotionTrigger": [{
49677
50018
  name: "deviceId",
49678
50019
  form: "single",
@@ -49683,6 +50024,11 @@ Object.freeze({
49683
50024
  form: "single",
49684
50025
  optional: false
49685
50026
  }],
50027
+ "motionZones.getStatus": [{
50028
+ name: "deviceId",
50029
+ form: "single",
50030
+ optional: false
50031
+ }],
49686
50032
  "motionZones.setZone": [{
49687
50033
  name: "deviceId",
49688
50034
  form: "single",
@@ -49693,6 +50039,11 @@ Object.freeze({
49693
50039
  form: "single",
49694
50040
  optional: false
49695
50041
  }],
50042
+ "nativeObjectDetection.getStatus": [{
50043
+ name: "deviceId",
50044
+ form: "single",
50045
+ optional: false
50046
+ }],
49696
50047
  "nativeObjectDetection.setEnabled": [{
49697
50048
  name: "deviceId",
49698
50049
  form: "single",
@@ -49708,6 +50059,11 @@ Object.freeze({
49708
50059
  form: "single",
49709
50060
  optional: false
49710
50061
  }],
50062
+ "navigation.getStatus": [{
50063
+ name: "deviceId",
50064
+ form: "single",
50065
+ optional: false
50066
+ }],
49711
50067
  "navigation.goToPoint": [{
49712
50068
  name: "deviceId",
49713
50069
  form: "single",
@@ -49753,6 +50109,11 @@ Object.freeze({
49753
50109
  form: "single",
49754
50110
  optional: false
49755
50111
  }],
50112
+ "networkLink.getStatus": [{
50113
+ name: "deviceId",
50114
+ form: "single",
50115
+ optional: false
50116
+ }],
49756
50117
  "networkQuality.getDeviceStats": [{
49757
50118
  name: "deviceId",
49758
50119
  form: "single",
@@ -49763,6 +50124,11 @@ Object.freeze({
49763
50124
  form: "single",
49764
50125
  optional: false
49765
50126
  }],
50127
+ "notificationRules.getAlarmSensors": [{
50128
+ name: "deviceIds",
50129
+ form: "array",
50130
+ optional: false
50131
+ }],
49766
50132
  "notificationRules.setDeviceMuted": [{
49767
50133
  name: "deviceId",
49768
50134
  form: "single",
@@ -49773,11 +50139,26 @@ Object.freeze({
49773
50139
  form: "single",
49774
50140
  optional: false
49775
50141
  }],
50142
+ "notifier.getStatus": [{
50143
+ name: "deviceId",
50144
+ form: "single",
50145
+ optional: false
50146
+ }],
49776
50147
  "notifier.send": [{
49777
50148
  name: "deviceId",
49778
50149
  form: "single",
49779
50150
  optional: false
49780
50151
  }],
50152
+ "numericSensor.getStatus": [{
50153
+ name: "deviceId",
50154
+ form: "single",
50155
+ optional: false
50156
+ }],
50157
+ "osd.getStatus": [{
50158
+ name: "deviceId",
50159
+ form: "single",
50160
+ optional: false
50161
+ }],
49781
50162
  "osd.setOverlay": [{
49782
50163
  name: "deviceId",
49783
50164
  form: "single",
@@ -49837,6 +50218,11 @@ Object.freeze({
49837
50218
  form: "single",
49838
50219
  optional: false
49839
50220
  }],
50221
+ "petFeeder.getStatus": [{
50222
+ name: "deviceId",
50223
+ form: "single",
50224
+ optional: false
50225
+ }],
49840
50226
  "petFeeder.markFoodReplenished": [{
49841
50227
  name: "deviceId",
49842
50228
  form: "single",
@@ -49872,6 +50258,11 @@ Object.freeze({
49872
50258
  form: "single",
49873
50259
  optional: false
49874
50260
  }],
50261
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
50262
+ name: "deviceId",
50263
+ form: "single",
50264
+ optional: false
50265
+ }],
49875
50266
  "pipelineAnalytics.clearTrackRelation": [{
49876
50267
  name: "deviceId",
49877
50268
  form: "single",
@@ -49912,6 +50303,16 @@ Object.freeze({
49912
50303
  form: "single",
49913
50304
  optional: false
49914
50305
  }],
50306
+ "pipelineAnalytics.getDeviceLiveContribution": [{
50307
+ name: "deviceId",
50308
+ form: "single",
50309
+ optional: false
50310
+ }],
50311
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
50312
+ name: "deviceId",
50313
+ form: "single",
50314
+ optional: false
50315
+ }],
49915
50316
  "pipelineAnalytics.getEventDensity": [{
49916
50317
  name: "deviceId",
49917
50318
  form: "single",
@@ -50127,6 +50528,11 @@ Object.freeze({
50127
50528
  form: "single",
50128
50529
  optional: true
50129
50530
  }],
50531
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
50532
+ name: "deviceId",
50533
+ form: "single",
50534
+ optional: false
50535
+ }],
50130
50536
  "pipelineOrchestrator.assignAudio": [{
50131
50537
  name: "deviceId",
50132
50538
  form: "single",
@@ -50172,6 +50578,16 @@ Object.freeze({
50172
50578
  form: "single",
50173
50579
  optional: false
50174
50580
  }],
50581
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
50582
+ name: "deviceId",
50583
+ form: "single",
50584
+ optional: false
50585
+ }],
50586
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
50587
+ name: "deviceId",
50588
+ form: "single",
50589
+ optional: false
50590
+ }],
50175
50591
  "pipelineOrchestrator.getPipelineAssignment": [{
50176
50592
  name: "deviceId",
50177
50593
  form: "single",
@@ -50292,11 +50708,31 @@ Object.freeze({
50292
50708
  form: "single",
50293
50709
  optional: true
50294
50710
  }],
50711
+ "powerMeter.getStatus": [{
50712
+ name: "deviceId",
50713
+ form: "single",
50714
+ optional: false
50715
+ }],
50716
+ "presence.getStatus": [{
50717
+ name: "deviceId",
50718
+ form: "single",
50719
+ optional: false
50720
+ }],
50721
+ "pressureSensor.getStatus": [{
50722
+ name: "deviceId",
50723
+ form: "single",
50724
+ optional: false
50725
+ }],
50295
50726
  "privacyMask.getOptions": [{
50296
50727
  name: "deviceId",
50297
50728
  form: "single",
50298
50729
  optional: false
50299
50730
  }],
50731
+ "privacyMask.getStatus": [{
50732
+ name: "deviceId",
50733
+ form: "single",
50734
+ optional: false
50735
+ }],
50300
50736
  "privacyMask.setAudioEnabled": [{
50301
50737
  name: "deviceId",
50302
50738
  form: "single",
@@ -50347,6 +50783,11 @@ Object.freeze({
50347
50783
  form: "single",
50348
50784
  optional: false
50349
50785
  }],
50786
+ "ptz.getStatus": [{
50787
+ name: "deviceId",
50788
+ form: "single",
50789
+ optional: false
50790
+ }],
50350
50791
  "ptz.goHome": [{
50351
50792
  name: "deviceId",
50352
50793
  form: "single",
@@ -50437,6 +50878,11 @@ Object.freeze({
50437
50878
  form: "single",
50438
50879
  optional: false
50439
50880
  }],
50881
+ "recordingArchive.applyDeviceSettingsPatch": [{
50882
+ name: "deviceId",
50883
+ form: "single",
50884
+ optional: false
50885
+ }],
50440
50886
  "recordingArchive.deleteFootprint": [{
50441
50887
  name: "deviceId",
50442
50888
  form: "single",
@@ -50457,6 +50903,21 @@ Object.freeze({
50457
50903
  form: "single",
50458
50904
  optional: false
50459
50905
  }],
50906
+ "recordingArchive.getDeviceLiveContribution": [{
50907
+ name: "deviceId",
50908
+ form: "single",
50909
+ optional: false
50910
+ }],
50911
+ "recordingArchive.getDeviceSettingsContribution": [{
50912
+ name: "deviceId",
50913
+ form: "single",
50914
+ optional: false
50915
+ }],
50916
+ "recordingArchive.getStatus": [{
50917
+ name: "deviceId",
50918
+ form: "single",
50919
+ optional: false
50920
+ }],
50460
50921
  "recordingArchive.listOpsLog": [{
50461
50922
  name: "deviceId",
50462
50923
  form: "single",
@@ -50542,6 +51003,11 @@ Object.freeze({
50542
51003
  form: "single",
50543
51004
  optional: false
50544
51005
  }],
51006
+ "recordingOnboard.getStatus": [{
51007
+ name: "deviceId",
51008
+ form: "single",
51009
+ optional: false
51010
+ }],
50545
51011
  "recordingOnboard.setSettings": [{
50546
51012
  name: "deviceId",
50547
51013
  form: "single",
@@ -50572,6 +51038,11 @@ Object.freeze({
50572
51038
  form: "single",
50573
51039
  optional: false
50574
51040
  }],
51041
+ "sceneMonitor.getStatus": [{
51042
+ name: "deviceId",
51043
+ form: "single",
51044
+ optional: false
51045
+ }],
50575
51046
  "sceneMonitor.listScenes": [{
50576
51047
  name: "deviceId",
50577
51048
  form: "single",
@@ -50597,6 +51068,11 @@ Object.freeze({
50597
51068
  form: "single",
50598
51069
  optional: false
50599
51070
  }],
51071
+ "scriptRunner.getStatus": [{
51072
+ name: "deviceId",
51073
+ form: "single",
51074
+ optional: false
51075
+ }],
50600
51076
  "scriptRunner.run": [{
50601
51077
  name: "deviceId",
50602
51078
  form: "single",
@@ -50607,11 +51083,31 @@ Object.freeze({
50607
51083
  form: "single",
50608
51084
  optional: false
50609
51085
  }],
51086
+ "smoke.getStatus": [{
51087
+ name: "deviceId",
51088
+ form: "single",
51089
+ optional: false
51090
+ }],
51091
+ "snapshot.applyDeviceSettingsPatch": [{
51092
+ name: "deviceId",
51093
+ form: "single",
51094
+ optional: false
51095
+ }],
50610
51096
  "snapshot.getDebugState": [{
50611
51097
  name: "deviceId",
50612
51098
  form: "single",
50613
51099
  optional: false
50614
51100
  }],
51101
+ "snapshot.getDeviceLiveContribution": [{
51102
+ name: "deviceId",
51103
+ form: "single",
51104
+ optional: false
51105
+ }],
51106
+ "snapshot.getDeviceSettingsContribution": [{
51107
+ name: "deviceId",
51108
+ form: "single",
51109
+ optional: false
51110
+ }],
50615
51111
  "snapshot.getSnapshot": [{
50616
51112
  name: "deviceId",
50617
51113
  form: "single",
@@ -50628,6 +51124,11 @@ Object.freeze({
50628
51124
  form: "array",
50629
51125
  optional: false
50630
51126
  }],
51127
+ "snapshot.getStatus": [{
51128
+ name: "deviceId",
51129
+ form: "single",
51130
+ optional: false
51131
+ }],
50631
51132
  "snapshot.invalidateCache": [{
50632
51133
  name: "deviceId",
50633
51134
  form: "single",
@@ -50638,6 +51139,11 @@ Object.freeze({
50638
51139
  form: "single",
50639
51140
  optional: false
50640
51141
  }],
51142
+ "streamBroker.applyDeviceSettingsPatch": [{
51143
+ name: "deviceId",
51144
+ form: "single",
51145
+ optional: false
51146
+ }],
50641
51147
  "streamBroker.assignProfile": [{
50642
51148
  name: "deviceId",
50643
51149
  form: "single",
@@ -50653,6 +51159,16 @@ Object.freeze({
50653
51159
  form: "single",
50654
51160
  optional: false
50655
51161
  }],
51162
+ "streamBroker.getDeviceLiveContribution": [{
51163
+ name: "deviceId",
51164
+ form: "single",
51165
+ optional: false
51166
+ }],
51167
+ "streamBroker.getDeviceSettingsContribution": [{
51168
+ name: "deviceId",
51169
+ form: "single",
51170
+ optional: false
51171
+ }],
50656
51172
  "streamBroker.getStreamWithCodec": [{
50657
51173
  name: "deviceId",
50658
51174
  form: "single",
@@ -50713,16 +51229,46 @@ Object.freeze({
50713
51229
  form: "single",
50714
51230
  optional: false
50715
51231
  }],
51232
+ "streamParams.getStatus": [{
51233
+ name: "deviceId",
51234
+ form: "single",
51235
+ optional: false
51236
+ }],
50716
51237
  "streamParams.setProfile": [{
50717
51238
  name: "deviceId",
50718
51239
  form: "single",
50719
51240
  optional: false
50720
51241
  }],
51242
+ "switch.getStatus": [{
51243
+ name: "deviceId",
51244
+ form: "single",
51245
+ optional: false
51246
+ }],
50721
51247
  "switch.setState": [{
50722
51248
  name: "deviceId",
50723
51249
  form: "single",
50724
51250
  optional: false
50725
51251
  }],
51252
+ "tamper.getStatus": [{
51253
+ name: "deviceId",
51254
+ form: "single",
51255
+ optional: false
51256
+ }],
51257
+ "temperatureSensor.getStatus": [{
51258
+ name: "deviceId",
51259
+ form: "single",
51260
+ optional: false
51261
+ }],
51262
+ "update.getStatus": [{
51263
+ name: "deviceId",
51264
+ form: "single",
51265
+ optional: false
51266
+ }],
51267
+ "vacuumControl.getStatus": [{
51268
+ name: "deviceId",
51269
+ form: "single",
51270
+ optional: false
51271
+ }],
50726
51272
  "vacuumControl.locate": [{
50727
51273
  name: "deviceId",
50728
51274
  form: "single",
@@ -50758,6 +51304,11 @@ Object.freeze({
50758
51304
  form: "single",
50759
51305
  optional: false
50760
51306
  }],
51307
+ "valve.getStatus": [{
51308
+ name: "deviceId",
51309
+ form: "single",
51310
+ optional: false
51311
+ }],
50761
51312
  "valve.open": [{
50762
51313
  name: "deviceId",
50763
51314
  form: "single",
@@ -50773,6 +51324,11 @@ Object.freeze({
50773
51324
  form: "single",
50774
51325
  optional: false
50775
51326
  }],
51327
+ "vibration.getStatus": [{
51328
+ name: "deviceId",
51329
+ form: "single",
51330
+ optional: false
51331
+ }],
50776
51332
  "videoclips.dialClipStream": [{
50777
51333
  name: "deviceId",
50778
51334
  form: "single",
@@ -50808,6 +51364,11 @@ Object.freeze({
50808
51364
  form: "single",
50809
51365
  optional: false
50810
51366
  }],
51367
+ "waterHeater.getStatus": [{
51368
+ name: "deviceId",
51369
+ form: "single",
51370
+ optional: false
51371
+ }],
50811
51372
  "waterHeater.setAway": [{
50812
51373
  name: "deviceId",
50813
51374
  form: "single",
@@ -50823,6 +51384,11 @@ Object.freeze({
50823
51384
  form: "single",
50824
51385
  optional: false
50825
51386
  }],
51387
+ "weather.getStatus": [{
51388
+ name: "deviceId",
51389
+ form: "single",
51390
+ optional: false
51391
+ }],
50826
51392
  "webrtcSession.addIceCandidate": [{
50827
51393
  name: "deviceId",
50828
51394
  form: "single",
@@ -51560,7 +52126,7 @@ var PreviewTextField = string().max(200);
51560
52126
  * Whether the notification's preview is a STILL or a short animation.
51561
52127
  *
51562
52128
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
51563
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
52129
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
51564
52130
  * night reads better as three seconds of motion than as one frame of it. Both
51565
52131
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
51566
52132
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -51698,6 +52264,7 @@ TimelapseRuleInputSchema.extend({
51698
52264
  createdAt: number(),
51699
52265
  updatedAt: number()
51700
52266
  });
52267
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
51701
52268
  object({
51702
52269
  /**
51703
52270
  * Fraction of the box's own size added on EACH side before cutting.