@camstack/addon-matter-broker 0.2.116 → 0.2.117

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +893 -326
  2. package/dist/addon.mjs +893 -326
  3. package/package.json +1 -3
package/dist/addon.mjs CHANGED
@@ -11,7 +11,7 @@ import { networkInterfaces, tmpdir, uptime } from "node:os";
11
11
  import { finished } from "node:stream/promises";
12
12
  import { createConnection, createServer as createServer$2 } from "node:net";
13
13
  import * as dgram from "node:dgram";
14
- //#region ../types/dist/event-category-C5xZWqz6.mjs
14
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
15
15
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
16
16
  EventCategory["SystemBoot"] = "system.boot";
17
17
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -544,6 +544,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
544
544
  */
545
545
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
546
546
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
547
+ /**
548
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
549
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
550
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
551
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
552
+ * for a camera with no attached sensor). Providers must not emit
553
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
554
+ * keeps it so (camera-grid is a named, deferred exception).
555
+ */
547
556
  EventCategory["ProviderMotion"] = "provider.motion";
548
557
  EventCategory["ProviderDetection"] = "provider.detection";
549
558
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5382,7 +5391,7 @@ var ZodIssueCode = {
5382
5391
  var ZodFirstPartyTypeKind;
5383
5392
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5384
5393
  //#endregion
5385
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5394
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5386
5395
  /**
5387
5396
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5388
5397
  * window to float samples (D455).
@@ -7425,7 +7434,7 @@ function errMsg(err) {
7425
7434
  return String(err);
7426
7435
  }
7427
7436
  //#endregion
7428
- //#region ../types/dist/composition-Dq42XWp0.mjs
7437
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
7429
7438
  /**
7430
7439
  * The ffmpeg build every CamStack node downloads, per platform and arch.
7431
7440
  *
@@ -7479,21 +7488,20 @@ function portable(target) {
7479
7488
  }
7480
7489
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
7481
7490
  /**
7482
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7483
- * valutatore puro del suo FRONTE.
7491
+ * THE table "which boolean of this device type counts as HIGH", and the
7492
+ * pure evaluator of its EDGE.
7484
7493
  *
7485
- * Viveva dentro il builtin virtual-doorbell
7486
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7487
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7488
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7489
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7490
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7491
- * SPOSTA qui e il doorbell la ri-esporta.
7494
+ * ONE table for everyone who asks "is this device HIGH?": the
7495
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
7496
+ * sensor markers, the orchestrator's camera-sensors bridge and
7497
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
7498
+ * A second copy would diverge at the first cap added, and the symptom — "the
7499
+ * sensor rings the doorbell but does not record" — is exactly D62.
7492
7500
  *
7493
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7494
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7495
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7496
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7501
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
7502
+ * two must not be unified: that one answers "what is the state WORD for a
7503
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
7504
+ * boolean's EDGE counts". Deliberately different vocabularies.
7497
7505
  */
7498
7506
  /**
7499
7507
  * Known binary / switch source caps → the boolean slice field whose
@@ -9102,22 +9110,22 @@ var CLASS_MAP_MACRO_TARGETS = [
9102
9110
  "package"
9103
9111
  ];
9104
9112
  /**
9105
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
9106
- * un operatore può selezionare.
9113
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
9114
+ * an operator can select.
9107
9115
  *
9108
- * Sono le tre offerte dallo step `object-detection`
9116
+ * They are the three offered by the `object-detection` step
9109
9117
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
9110
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
9111
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
9112
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
9113
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
9118
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
9119
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
9120
+ * `package-detection`, whose enablement is driven by zones, and offering the
9121
+ * same word twice has already made an operator turn on the COCO proxy
9114
9122
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
9115
9123
  *
9116
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
9117
- * dello step e una seconda volta come union `FirstLevelMacro`
9118
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
9119
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
9120
- * successiva.
9124
+ * ONE list. Before today the same three were hand-written in the step's offer
9125
+ * and a second time as the union `FirstLevelMacro`
9126
+ * (`types/detection.ts`); a third copy for the recording trigger
9127
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
9128
+ * invisible.
9121
9129
  */
9122
9130
  var FIRST_LEVEL_MACRO_CLASSES = [
9123
9131
  "person",
@@ -9182,17 +9190,17 @@ var RecordingStorageModeSchema = _enum([
9182
9190
  "on-device-decision"
9183
9191
  ]);
9184
9192
  /**
9185
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
9186
- * tre offerte dallo step `object-detection`, da UNA lista
9193
+ * The macro classes that can open a recording window — the same
9194
+ * three offered by the `object-detection` step, from ONE list
9187
9195
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
9188
9196
  */
9189
9197
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
9190
9198
  /**
9191
- * True quando `values` non ripete un elemento.
9199
+ * True when `values` does not repeat an element.
9192
9200
  *
9193
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
9194
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
9195
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
9201
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
9202
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
9203
+ * would count its windows twice in `segmentMissedByMs`.
9196
9204
  */
9197
9205
  var noDuplicates = (values) => new Set(values).size === values.length;
9198
9206
  /** Which detectors trigger an `events`-mode band. */
@@ -9200,34 +9208,34 @@ var RecordingTriggersSchema = object({
9200
9208
  motion: boolean().optional(),
9201
9209
  audioThresholdDbfs: number().optional(),
9202
9210
  /**
9203
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
9204
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
9205
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
9206
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
9211
+ * The macro classes whose detection opens a window. ABSENT = the source
9212
+ * is not listened to; an EMPTY array is rejected, because "events band, object
9213
+ * trigger on, no class" is the same shape "enabled and records
9214
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
9207
9215
  *
9208
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
9209
- * quelle che hanno attraversato `enabledMacroClasses`, i
9210
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
9211
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
9212
- * finestre — vedi `recorder/object-trigger.ts`.
9216
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
9217
+ * those that went through `enabledMacroClasses`, the
9218
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
9219
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
9220
+ * windows — see `recorder/object-trigger.ts`.
9213
9221
  */
9214
9222
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
9215
9223
  /**
9216
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
9217
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
9224
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
9225
+ * is not listened to; an empty array is rejected for the same reason as
9218
9226
  * `objectClasses`.
9219
9227
  *
9220
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
9221
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
9222
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
9223
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9224
- * device (D12) — mai un elenco globale di cap.
9228
+ * These are SOURCE device ids, not cameras: the band names them, so the
9229
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
9230
+ * does no RPC. The OFFER from which the operator picks them is another question, and
9231
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9232
+ * device (D12) — never a global list of caps.
9225
9233
  *
9226
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9227
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9228
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9229
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
9230
- * registrare.
9234
+ * What "high" means depends on the device TYPE and is not decided here:
9235
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
9236
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
9237
+ * the level: a contact found already open at runner restart does not
9238
+ * record.
9231
9239
  */
9232
9240
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9233
9241
  });
@@ -10304,7 +10312,7 @@ var DecoderSessionConfigSchema = object({
10304
10312
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
10305
10313
  * thing: the logging settings document on the `system` cap. Two authorities
10306
10314
  * over the values is the exact defect
10307
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
10315
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
10308
10316
  * remove; re-introducing it from the cure side would be grotesque.
10309
10317
  *
10310
10318
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -12015,7 +12023,7 @@ var BrokerStatusEnum = _enum([
12015
12023
  "unreachable",
12016
12024
  "error"
12017
12025
  ]);
12018
- var BrokerInfoSchema$1 = object({
12026
+ var BrokerInfoSchema = object({
12019
12027
  /** Stable broker id. Persisted; survives addon restarts. */
12020
12028
  id: string$2(),
12021
12029
  /** Addon id of the provider that OWNS this broker.
@@ -12158,8 +12166,8 @@ var brokerCapability = {
12158
12166
  kind: "poll"
12159
12167
  },
12160
12168
  methods: {
12161
- list: method(ListInputSchema, array(BrokerInfoSchema$1)),
12162
- get: method(GetInputSchema, BrokerInfoSchema$1.nullable()),
12169
+ list: method(ListInputSchema, array(BrokerInfoSchema)),
12170
+ get: method(GetInputSchema, BrokerInfoSchema.nullable()),
12163
12171
  /** Enumerate which addon provides which broker kind(s) for the
12164
12172
  * unified create picker. The auto-mount fans this array across
12165
12173
  * every registered `broker` provider (array-output method), so the
@@ -13908,7 +13916,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
13908
13916
  *
13909
13917
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
13910
13918
  * was wrong — corrected 2026-08-26 after the hop map
13911
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
13919
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
13912
13920
  * There is **no Zod parse at all** between the door and the engine: the
13913
13921
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
13914
13922
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -14788,7 +14796,17 @@ var SiteZoneSchema = object({
14788
14796
  var ProviderStatusSchema = object({
14789
14797
  connected: boolean(),
14790
14798
  deviceCount: number(),
14791
- error: string$2().optional()
14799
+ error: string$2().optional(),
14800
+ /**
14801
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14802
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14803
+ * which every provider bundles, so only a provider BUILT from D696-amended
14804
+ * code says it. ABSENT means an older provider that may still write it (raw
14805
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14806
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14807
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14808
+ */
14809
+ motionSliceWriter: literal("orchestrator").optional()
14792
14810
  });
14793
14811
  object({
14794
14812
  externalId: string$2(),
@@ -15667,109 +15685,10 @@ method(object({
15667
15685
  deviceIds: array(number()).readonly(),
15668
15686
  caps: array(string$2()).readonly().optional()
15669
15687
  }), record(string$2(), record(string$2(), unknown().nullable())));
15670
- /**
15671
- * Doorbell button cap. Two kinds of providers coexist behind this cap
15672
- * name (same pattern as `snapshot`):
15673
- *
15674
- * - **Native** providers: registered per-device by device-driver
15675
- * addons via `ctx.registerNativeCap` — either on a
15676
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
15677
- * or directly on the camera (Reolink registers at camera level).
15678
- * Emits an `onPressed` event every time the firmware pushes a
15679
- * ring; status tracks the last press and a pressCount since start
15680
- * (diagnostic).
15681
- *
15682
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
15683
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
15684
- * device (contact / switch / event-emitter …) into a doorbell for
15685
- * a camera. `defaultActive: false` — the operator explicitly binds
15686
- * it per camera in the device-bindings UI, then picks the source
15687
- * device + trigger in the per-device settings.
15688
- *
15689
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
15690
- * — subscribers listening at the camera level receive ring events
15691
- * with `via[]` populated. No code on the parent needed.
15692
- */
15693
- var DoorbellStatusSchema = object({
15694
- /** Ms epoch of the last press. null = never observed since this provider started. */
15695
- lastPressedAt: number().nullable(),
15696
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15697
- pressCountSinceStart: number()
15698
- });
15699
- var DoorbellPressEventSchema = object({
15700
- deviceId: number(),
15701
- timestamp: number()
15702
- });
15703
- /**
15704
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15705
- * virtual-doorbell trigger devices, exactly what the wrapper's
15706
- * `doorbellSources` persists (as `{ deviceId }` records).
15707
- */
15708
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15709
- /**
15710
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
15711
- * doorbell, owned by the `virtual-doorbell` wrapper over its
15712
- * `doorbellSources` store (D648). A source rings when one of its
15713
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
15714
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
15715
- * reports it, it never writes it.
15716
- */
15717
- var DOORBELL_SOURCE_SLOT = {
15718
- id: "doorbell-source",
15719
- label: "Doorbell trigger devices",
15720
- 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.",
15721
- shape: "association",
15722
- hostDeviceTypes: [DeviceType.Camera],
15723
- sourceCaps: SOURCE_CAPS,
15724
- cardinality: "many",
15725
- value: DoorbellSourceSlotValueSchema
15726
- };
15727
- var doorbellCapability = {
15728
- name: "doorbell",
15729
- scope: "device",
15730
- deviceNative: true,
15731
- mode: "singleton",
15732
- kind: "wrapper",
15733
- defaultActive: false,
15734
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
15735
- extensionSlots: [DOORBELL_SOURCE_SLOT],
15736
- methods: {},
15737
- events: {
15738
- /**
15739
- * Fires once per physical press. Reolink delivers via Baichuan
15740
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
15741
- * release/duration — it's a pulse.
15742
- */
15743
- onPressed: {
15744
- data: DoorbellPressEventSchema,
15745
- fromState: {
15746
- field: "lastPressedAt",
15747
- on: "advance"
15748
- }
15749
- } },
15750
- status: {
15751
- schema: DoorbellStatusSchema,
15752
- kind: "push"
15753
- },
15754
- /**
15755
- * Runtime-state slice — last press timestamp + lifetime press count.
15756
- * Mirrored by the kernel and readable via
15757
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
15758
- * without subscribing.
15759
- */
15760
- runtimeState: DoorbellStatusSchema,
15761
- /**
15762
- * 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.
15763
- *
15764
- * See `RuntimeStateDurability`. Enforced by
15765
- * `scripts/check-runtime-state-durability.ts`.
15766
- */
15767
- durability: "restored"
15768
- };
15769
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15770
- DeviceType.Camera, DeviceType.Camera;
15688
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15689
+ DeviceType.Camera;
15771
15690
  /** A slot's editable value, discriminated on `slot`. */
15772
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15691
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15773
15692
  DeviceType.Camera;
15774
15693
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15775
15694
  state: literal("unreachable"),
@@ -15806,10 +15725,11 @@ var ExtensionSlotSourceSchema = object({
15806
15725
  });
15807
15726
  /**
15808
15727
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15809
- * reported read-only, named, never written through this contract (D62). The
15810
- * virtual doorbell's sources ring only while the wrapper is bound to the
15811
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15812
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15728
+ * reported read-only, named, never written through this contract (D62) — e.g.
15729
+ * a slot whose sources act only while a wrapper is bound to the host, a
15730
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15731
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15732
+ * not be read; it is not "inactive" (D315).
15813
15733
  */
15814
15734
  var ExtensionSlotActivationSchema = object({
15815
15735
  state: _enum([
@@ -15825,7 +15745,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15825
15745
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15826
15746
  slotRef: string$2(),
15827
15747
  slot: ExtensionSlotIdSchema,
15828
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15748
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15829
15749
  authority: string$2(),
15830
15750
  activation: ExtensionSlotActivationSchema.nullable(),
15831
15751
  value: ExtensionSlotValueSchema,
@@ -16103,7 +16023,7 @@ method(object({
16103
16023
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16104
16024
  * ends in a log line, and a log line is the thing the operator asked to stop
16105
16025
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16106
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
16026
+ * 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
16107
16027
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16108
16028
  * media blackout were both diagnosed. The counters stay; this is where they can
16109
16029
  * be READ.
@@ -17479,7 +17399,7 @@ var BrokerStatusSchema$1 = _enum([
17479
17399
  "unreachable",
17480
17400
  "tls-error"
17481
17401
  ]);
17482
- var BrokerInfoSchema = object({
17402
+ var BrokerInfoSchema$1 = object({
17483
17403
  id: string$2(),
17484
17404
  name: string$2(),
17485
17405
  url: string$2(),
@@ -17542,7 +17462,7 @@ var StatusSchema = object({
17542
17462
  brokerCount: number(),
17543
17463
  embeddedRunning: boolean()
17544
17464
  });
17545
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17465
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17546
17466
  kind: "mutation",
17547
17467
  auth: "admin"
17548
17468
  }), method(IdInputSchema, _void(), {
@@ -19756,78 +19676,16 @@ var NcRuleInputSchema = object({
19756
19676
  */
19757
19677
  confirm: NcConfirmSchema.optional(),
19758
19678
  /**
19759
- * WAIT for face/plate recognition before saying anything.
19760
- *
19761
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
19762
- * send; the identity is neither. A face is confirmed after `confirmFrames`
19763
- * agreeing observations — p50 **11.4 s** after the track was first seen,
19764
- * measured on this hub — and an `immediate` rule enqueues on the first object
19765
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
19766
- * immediate path, and no amount of media re-resolution fixes a sentence.
19767
- *
19768
- * Only two honest answers exist, and this flag picks between them. It has
19769
- * effect ONLY on a rule that declares a recognition scope
19770
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
19771
- * other rule there is nothing to wait for and the flag is inert.
19772
- *
19773
- * | value | what happens |
19774
- * | --- | --- |
19775
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
19776
- * | 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) |
19777
- *
19778
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19779
- * on the addon cap path, and absent has to keep meaning exactly what every
19780
- * rule authored before this field meant.
19781
- *
19782
- * The cost of `true` is stated here because the editor states it too: a rule
19783
- * that waits also inherits track-close SEMANTICS — its `zones` condition
19784
- * tests every zone the track visited and a `crossing` condition can no longer
19785
- * be satisfied, because a closed track carries no crossing.
19786
- */
19787
- waitForEnhancement: boolean().optional(),
19788
- /**
19789
- * GROUP a burst of subjects into ONE notification that grows.
19790
- *
19791
- * Seconds of quiet after the last matching subject before the burst is
19792
- * considered over. While it is open, the first subject enqueues immediately —
19793
- * **exactly as today, with no added latency** — and every real growth (a new
19794
- * subject, or a name confirmed on one already in it) REPLACES that
19795
- * notification with an updated one naming everybody. The push carries the
19796
- * group's own coalescing tag, so the phone replaces rather than stacks.
19797
- *
19798
- * `0` / absent = off, and off is today's behaviour byte for byte.
19799
- *
19800
- * ### Why an idle cutoff and not a window
19801
- *
19802
- * The measured seven-person arrival on device 590 spans 110 s with every
19803
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
19804
- * idle cutoff holds it as one and ends it when the arrival actually ends.
19805
- * 30 s is a widely shipped value for the same decision.
19806
- *
19807
- * ### What it replaces
19808
- *
19809
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
19810
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
19811
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
19812
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
19813
- * A group collapses the same volume by MERGING, so the cooldown becomes a
19814
- * budget over GROUPS — which is what it always meant — and a growth is never
19815
- * throttled by the window its own first member spent.
19816
- *
19817
- * ### Interaction with {@link waitForEnhancement}
19818
- *
19819
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
19820
- * TRACK CLOSE, so with both set the group is opened by the first member to
19821
- * CLOSE — already carrying its name — and grows as later members close. That
19822
- * is later, and complete. With grouping alone the group opens on the first
19823
- * object event and picks up names as they are confirmed, through the growth
19824
- * path. Neither combination fires twice for one subject.
19825
- *
19826
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19827
- * on the addon cap path, so absent must keep meaning what it meant before this
19828
- * field existed.
19679
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
19680
+ * seconds; the rule sends ONE message when the window closes — early, once every
19681
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
19682
+ * the rule matched, with one mosaic tile per subject.
19683
+ * Absent = plain immediate (one message per track, at the first match).
19684
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
19685
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
19686
+ * path does not run Zod defaults.
19829
19687
  */
19830
- groupIdleSec: number().int().min(0).max(600).optional()
19688
+ groupingSec: number().int().min(5).max(60).optional()
19831
19689
  });
19832
19690
  /**
19833
19691
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -19875,9 +19733,10 @@ var NcRuleClearableKeySchema = _enum([
19875
19733
  "targetUsers",
19876
19734
  "snoozeOptions",
19877
19735
  "snoozeAllowGlobal",
19878
- "waitForEnhancement",
19879
19736
  "actions",
19880
19737
  "confirm",
19738
+ "groupingSec",
19739
+ "waitForEnhancement",
19881
19740
  "groupIdleSec"
19882
19741
  ]);
19883
19742
  var NcRuleUpdateInputSchema = object({
@@ -19899,9 +19758,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19899
19758
  */
19900
19759
  disabledTargetIds: array(string$2()).default([])
19901
19760
  });
19761
+ /**
19762
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19763
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
19764
+ * job is not an open state, and the alarm stays instant.
19765
+ */
19766
+ var NcStateSummarySectionIdSchema = _enum([
19767
+ "device-state",
19768
+ "streams",
19769
+ "battery",
19770
+ "consumables",
19771
+ "tanks",
19772
+ "detection-blind",
19773
+ "nodes",
19774
+ "addons",
19775
+ "updates"
19776
+ ]);
19902
19777
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
19903
19778
  var NcStateSummaryPreviewSectionSchema = object({
19904
- id: string$2(),
19779
+ id: NcStateSummarySectionIdSchema,
19905
19780
  status: _enum(["read", "unavailable"]),
19906
19781
  items: number().int().nonnegative(),
19907
19782
  reason: string$2().optional()
@@ -19911,7 +19786,7 @@ var NcStateSummaryPreviewSectionSchema = object({
19911
19786
  * a `rule` split (no `section`), one section's on a `section` split.
19912
19787
  */
19913
19788
  var NcStateSummaryPreviewRowSchema = object({
19914
- section: string$2().optional(),
19789
+ section: NcStateSummarySectionIdSchema.optional(),
19915
19790
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19916
19791
  title: string$2(),
19917
19792
  text: string$2(),
@@ -20348,6 +20223,29 @@ object({
20348
20223
  firstAt: number(),
20349
20224
  lastAt: number()
20350
20225
  });
20226
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20227
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20228
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20229
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20230
+ var NcAlarmModeDelaysListSchema = array(object({
20231
+ mode: AlarmArmModeSchema,
20232
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20233
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20234
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20235
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20236
+ var NcAlarmModeDelaysEditListSchema = array(object({
20237
+ mode: AlarmArmModeSchema,
20238
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20239
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20240
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20241
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20242
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20243
+ var NcAlarmNonBlockingEditSchema = object({
20244
+ mode: AlarmArmModeSchema,
20245
+ deviceId: number().int().positive(),
20246
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20247
+ nonBlocking: boolean()
20248
+ });
20351
20249
  /**
20352
20250
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20353
20251
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20356,10 +20254,10 @@ object({
20356
20254
  var NcAlarmNonBlockingListSchema = array(object({
20357
20255
  mode: AlarmArmModeSchema,
20358
20256
  deviceIds: array(number().int()).max(200)
20359
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20257
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20360
20258
  /**
20361
- * The three durations the panel's state machine runs on, who hears about its
20362
- * transitions, and which openings each mode tolerates.
20259
+ * The three durations — global, and per mode since D697 — the panel's state
20260
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20363
20261
  *
20364
20262
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20365
20263
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20369,15 +20267,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20369
20267
  */
20370
20268
  var NcAlarmSettingsSchema = object({
20371
20269
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20372
- exitDelaySec: number().int().min(0).max(600),
20270
+ exitDelaySec: NcAlarmDelaySecSchema,
20373
20271
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20374
- entryDelaySec: number().int().min(0).max(600),
20272
+ entryDelaySec: NcAlarmDelaySecSchema,
20375
20273
  /**
20376
20274
  * How long `triggered` lasts before the panel re-arms itself.
20377
20275
  * **0 = until an operator disarms it** — the behaviour before this field
20378
20276
  * existed, and therefore what an untouched install keeps doing.
20379
20277
  */
20380
- triggeredDurationSec: number().int().min(0).max(3600),
20278
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20381
20279
  /**
20382
20280
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20383
20281
  * remove after one release. Optional so an older admin's patch (which still
@@ -20400,17 +20298,30 @@ var NcAlarmSettingsSchema = object({
20400
20298
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20401
20299
  * parses as "every opening blocks" — the behaviour it was written under.
20402
20300
  */
20403
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20301
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20302
+ /**
20303
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20304
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20305
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20306
+ */
20307
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20404
20308
  });
20405
20309
  /**
20406
20310
  * Every field optional — a tab edits one control at a time.
20407
20311
  *
20408
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20409
- * remove an inner `.default()`, so a patch that never named the field would
20410
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20411
- * (the same trap {@link NcRulePatchSchema} documents).
20312
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20313
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20314
+ * named the field would parse to `[]` and wipe every mode's list on an
20315
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20316
+ * `modeDelays` means EDITS, not the stored overrides.
20412
20317
  */
20413
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20318
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20319
+ nonBlocking: NcAlarmNonBlockingListSchema,
20320
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20321
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20322
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20323
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20324
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20414
20325
  /**
20415
20326
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20416
20327
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20510,6 +20421,28 @@ var NcAlarmConfigSchema = object({
20510
20421
  */
20511
20422
  live: NcAlarmLiveSchema.optional()
20512
20423
  });
20424
+ var NcAlarmSensorReadingSchema = _enum([
20425
+ "open",
20426
+ "closed",
20427
+ "unknown",
20428
+ "not-opening"
20429
+ ]);
20430
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20431
+ var NcAlarmSensorStateSchema = object({
20432
+ deviceId: number().int().positive(),
20433
+ reading: NcAlarmSensorReadingSchema,
20434
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20435
+ state: string$2().nullable(),
20436
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20437
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20438
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20439
+ online: boolean().nullable()
20440
+ });
20441
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20442
+ var NcAlarmSensorsSchema = object({
20443
+ sensors: array(NcAlarmSensorStateSchema),
20444
+ readAt: number().int().nonnegative()
20445
+ });
20513
20446
  /**
20514
20447
  * ONE rule's demand on ONE camera's clip ring.
20515
20448
  *
@@ -20600,7 +20533,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20600
20533
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20601
20534
  kind: "mutation",
20602
20535
  auth: "admin"
20603
- });
20536
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20604
20537
  /**
20605
20538
  * Zod schemas for persisted record types.
20606
20539
  *
@@ -20947,12 +20880,26 @@ var CameraSensorRefSchema = object({
20947
20880
  function cameraSensorRefKey(ref) {
20948
20881
  return `${ref.addonId}/${ref.stableId}`;
20949
20882
  }
20950
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20951
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20952
- var CameraSensorsConfigSchema = object({
20953
- mode: CameraSensorsModeSchema,
20954
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20955
- }).superRefine((value, ctx) => {
20883
+ /**
20884
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20885
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20886
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20887
+ * camera's own motion counts only while a confirm sensor is active — with or
20888
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20889
+ */
20890
+ var CameraSensorModeSchema = _enum([
20891
+ "in-addition",
20892
+ "confirm",
20893
+ "replace"
20894
+ ]);
20895
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20896
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20897
+ /**
20898
+ * A camera's attached sensors. A CS-1 row carried an envelope
20899
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20900
+ * what the write stores (D672 rule 3), so it is never written again.
20901
+ */
20902
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20956
20903
  const seen = /* @__PURE__ */ new Set();
20957
20904
  value.sensors.forEach((ref, index) => {
20958
20905
  const key = cameraSensorRefKey(ref);
@@ -20964,39 +20911,41 @@ var CameraSensorsConfigSchema = object({
20964
20911
  seen.add(key);
20965
20912
  });
20966
20913
  });
20967
- var RefFields = {
20914
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20915
+ var AttachmentFields = {
20968
20916
  addonId: string$2(),
20969
- stableId: string$2()
20917
+ stableId: string$2(),
20918
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20970
20919
  };
20971
20920
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20972
20921
  object({
20973
- ...RefFields,
20922
+ ...AttachmentFields,
20974
20923
  state: literal("ready"),
20975
20924
  deviceId: number(),
20976
20925
  name: string$2(),
20977
20926
  caps: array(string$2()).readonly()
20978
20927
  }),
20979
20928
  object({
20980
- ...RefFields,
20929
+ ...AttachmentFields,
20981
20930
  state: literal("offline"),
20982
20931
  deviceId: number(),
20983
20932
  name: string$2(),
20984
20933
  reason: _enum(["offline", "disabled"])
20985
20934
  }),
20986
20935
  object({
20987
- ...RefFields,
20936
+ ...AttachmentFields,
20988
20937
  state: literal("missing"),
20989
20938
  reason: string$2()
20990
20939
  }),
20991
20940
  object({
20992
- ...RefFields,
20941
+ ...AttachmentFields,
20993
20942
  state: literal("unsupported"),
20994
20943
  deviceId: number(),
20995
20944
  name: string$2(),
20996
20945
  reason: string$2()
20997
20946
  }),
20998
20947
  object({
20999
- ...RefFields,
20948
+ ...AttachmentFields,
21000
20949
  state: literal("unreadable"),
21001
20950
  reason: string$2()
21002
20951
  })
@@ -21009,17 +20958,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
21009
20958
  * say.
21010
20959
  */
21011
20960
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20961
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20962
+ var CameraOwnMotionSchema = _enum([
20963
+ "always",
20964
+ "when-confirmed",
20965
+ "never"
20966
+ ]);
20967
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20968
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20969
+ /**
20970
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20971
+ * never the effective value. The camera's `motion` slice is the effective one,
20972
+ * so a view of the camera's own row reads this.
20973
+ * - `atMs`: when the bridge received the camera's last own edge.
20974
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20975
+ * AND it is younger than the window the bridge counts the camera's own motion
20976
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20977
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20978
+ * within the window; a status read is a snapshot, so a live view re-asks.
20979
+ * Absent = this orchestrator has not received the camera's own motion since it
20980
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20981
+ */
20982
+ var CameraRawLevelSchema = object({
20983
+ detected: boolean(),
20984
+ atMs: number()
20985
+ });
21012
20986
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
21013
- object({ state: literal("not-configured") }),
20987
+ object({
20988
+ state: literal("not-configured"),
20989
+ cameraLevel: CameraRawLevelSchema.optional()
20990
+ }),
21014
20991
  object({
21015
20992
  state: literal("unreadable"),
21016
- reason: string$2()
20993
+ reason: string$2(),
20994
+ cameraLevel: CameraRawLevelSchema.optional()
21017
20995
  }),
21018
20996
  object({
21019
20997
  state: literal("configured"),
21020
- mode: CameraSensorsModeSchema,
20998
+ cameraLevel: CameraRawLevelSchema.optional(),
21021
20999
  sensors: array(CameraSensorAttachmentSchema).readonly(),
21022
- notForwarded: CameraSensorsNotForwardedSchema.optional()
21000
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
21001
+ cameraMotion: CameraOwnMotionSchema.optional(),
21002
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
21003
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
21023
21004
  })
21024
21005
  ]);
21025
21006
  Object.freeze({
@@ -21704,14 +21685,14 @@ var TrackSchema = object({
21704
21685
  * `derive-returned-null tile=standin`,
21705
21686
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
21706
21687
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
21707
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
21688
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
21708
21689
  * tile is a face/plate stand-in, a raster crop, or an icon.
21709
21690
  *
21710
21691
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
21711
21692
  * the TILE ranked below native, so a track whose thumbnail landed natively
21712
21693
  * while its key frame missed carried no reason at all — three of the four
21713
21694
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
21714
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
21695
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
21715
21696
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
21716
21697
  * lastFrame copy source`), so its absence is now on this line whatever the
21717
21698
  * tile ended up being.
@@ -21798,7 +21779,7 @@ var MotionEventSchema = object({
21798
21779
  /**
21799
21780
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
21800
21781
  * first entry is always `0`) of every genuine off→on transition the
21801
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
21782
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
21802
21783
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
21803
21784
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
21804
21785
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -22322,6 +22303,7 @@ var KeyEventSchema = object({
22322
22303
  bestEventId: string$2(),
22323
22304
  /** Track lifetime in ms (lastSeen - firstSeen). */
22324
22305
  windowMs: number().optional(),
22306
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
22325
22307
  ...TrackFlagFields,
22326
22308
  ...TrackRetrainFields
22327
22309
  });
@@ -24250,8 +24232,10 @@ var RunnerCameraConfigSchema = object({
24250
24232
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24251
24233
  * analyzer providers) running on decoded frames in this runner.
24252
24234
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24253
- * analytics). The provider emits ProviderMotion
24254
- * events; the orchestrator forwards to `reportMotion`.
24235
+ * analytics). The provider emits its raw push as `ProviderMotion`
24236
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24237
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24238
+ * `reportMotion`.
24255
24239
  */
24256
24240
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24257
24241
  /**
@@ -24428,7 +24412,15 @@ var RunnerLocalLoadSchema = object({
24428
24412
  hasGpu: boolean(),
24429
24413
  inferenceBackend: string$2().optional(),
24430
24414
  cpuCores: number().optional()
24431
- })
24415
+ }),
24416
+ /**
24417
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24418
+ * runner never writes it. ABSENT = a runner older than D696, which still
24419
+ * writes the slice from its phase machine; the orchestrator does not write
24420
+ * while any runner node is absent-or-unanswered, so one slice never has two
24421
+ * writers.
24422
+ */
24423
+ motionSliceWriter: literal("orchestrator").optional()
24432
24424
  });
24433
24425
  /**
24434
24426
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -27093,7 +27085,7 @@ var ClipPlaybackSchema = object({
27093
27085
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
27094
27086
  * time the camera is awake for its own reasons — is deliberately not a member:
27095
27087
  * it was proposed, it is free on the battery, and the operator declined it on
27096
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
27088
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
27097
27089
  * D558 "Considered and not taken").
27098
27090
  */
27099
27091
  var ClipWakeSchema = _enum(["authorised"]);
@@ -27354,7 +27346,7 @@ DeviceType.Camera, method(object({
27354
27346
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
27355
27347
  * assumed the answer was a fan-out over everything a camera has. The
27356
27348
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
27357
- * solo"* — so the list is asked of one provider at a time and there is
27349
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
27358
27350
  * nothing to filter out of it.
27359
27351
  */
27360
27352
  provider: string$2().min(1)
@@ -29966,6 +29958,70 @@ onStatusChanged: { data: object({
29966
29958
  * whether persisting is worth a SQLite commit. */
29967
29959
  volatileStateFields: ["lastChangedAt"]
29968
29960
  };
29961
+ var DoorbellStatusSchema = object({
29962
+ /** Ms epoch of the last press. null = never observed since this provider started. */
29963
+ lastPressedAt: number().nullable(),
29964
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
29965
+ pressCountSinceStart: number()
29966
+ });
29967
+ var DoorbellPressEventSchema = object({
29968
+ deviceId: number(),
29969
+ timestamp: number()
29970
+ });
29971
+ /**
29972
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
29973
+ * they are the same cap:
29974
+ *
29975
+ * - **Native** providers, registered per device by a driver addon through
29976
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
29977
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
29978
+ * camera level). They emit `onPressed` on every firmware ring.
29979
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
29980
+ * the cap, its `lastPressedAt` rising from the sources the operator
29981
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
29982
+ * from that field's advance (`fromState`).
29983
+ *
29984
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
29985
+ */
29986
+ var doorbellCapability = {
29987
+ name: "doorbell",
29988
+ scope: "device",
29989
+ deviceNative: true,
29990
+ mode: "singleton",
29991
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
29992
+ methods: {},
29993
+ events: {
29994
+ /**
29995
+ * Fires once per physical press. Reolink delivers via Baichuan
29996
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
29997
+ * release/duration — it's a pulse.
29998
+ */
29999
+ onPressed: {
30000
+ data: DoorbellPressEventSchema,
30001
+ fromState: {
30002
+ field: "lastPressedAt",
30003
+ on: "advance"
30004
+ }
30005
+ } },
30006
+ status: {
30007
+ schema: DoorbellStatusSchema,
30008
+ kind: "push"
30009
+ },
30010
+ /**
30011
+ * Runtime-state slice — last press timestamp + lifetime press count.
30012
+ * Mirrored by the kernel and readable via
30013
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
30014
+ * without subscribing.
30015
+ */
30016
+ runtimeState: DoorbellStatusSchema,
30017
+ /**
30018
+ * 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.
30019
+ *
30020
+ * See `RuntimeStateDurability`. Enforced by
30021
+ * `scripts/check-runtime-state-durability.ts`.
30022
+ */
30023
+ durability: "restored"
30024
+ };
29969
30025
  /**
29970
30026
  * Enum-state sensor — a string value picked from a finite option set.
29971
30027
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -32110,9 +32166,9 @@ var MotionStatusSchema = object({
32110
32166
  /** Ms epoch of the last detected-true observation. Null if never detected. */
32111
32167
  lastDetectedAt: number().nullable(),
32112
32168
  /**
32113
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
32114
- * `null` while false and on every `Sensor` device (D475) — see that
32115
- * constant's doc for the one-authority rule.
32169
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
32170
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
32171
+ * device (D475) — see that constant's doc for the one-authority rule.
32116
32172
  *
32117
32173
  * ## Reading this field still arms nothing
32118
32174
  *
@@ -32130,34 +32186,31 @@ var MotionStatusSchema = object({
32130
32186
  * `addon-export-alexa/src/motion-clear-hold.ts` and
32131
32187
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
32132
32188
  *
32133
- * ## Who writes it
32134
- *
32135
- * - **Cameras** — the runner's phase machine, `active → watching` on
32136
- * `cooldown_expired`, which then writes this slice with
32137
- * `detected: false` (`handlePhaseChanged` in
32138
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
32139
- * matters most for the sources that only ever push a rising one:
32140
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
32141
- * a false.
32142
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
32143
- * provider pushes the false itself, from the upstream system's own
32144
- * state change. No phase machine is involved.
32145
- *
32146
- * ### The phase machine is CANONICAL, not sole — and that is a defect
32147
- *
32148
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
32149
- * phase machine is the sole writer for a camera. It is not.
32150
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
32151
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
32152
- * Hikvision's comment says why: it read THIS docblock, agreed the
32153
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
32154
- * two authorities can disagree about one slice, which this repo
32155
- * forbids, and the doc said otherwise — which is worse than saying
32156
- * nothing, because it reads as verification.
32157
- *
32158
- * This predates D475 and is not fixed there: the fix touches every
32159
- * camera provider. Recorded in D475's Consequences. Do not restore the
32160
- * "sole writer" wording without also removing the other writers.
32189
+ * ## Who writes it (D696)
32190
+ *
32191
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
32192
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
32193
+ * `camera-sensors/motion-slice.ts`), alongside the effective
32194
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
32195
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
32196
+ * device activity, as the camera's `motionSources` counts them. A source
32197
+ * that never sends a clear falls one window after its last `true`.
32198
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
32199
+ * writes this slice (not even a boot seed), and neither does the runner's
32200
+ * phase machine: its phase is "a session is attached" for every on-motion
32201
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
32202
+ * A provider's `isDetected` answers from the hub's slice.
32203
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32204
+ * imports) — the provider pushes both edges itself, from the upstream
32205
+ * system's own state change. That is the sensor's own fact.
32206
+ *
32207
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
32208
+ * `motion` slice; each sensor writer is a named exemption.
32209
+ *
32210
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
32211
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
32212
+ * it, every provider seeded it at boot, and every session left it
32213
+ * `detected: true` after its detach.
32161
32214
  */
32162
32215
  autoClearAfterMs: number().nullable()
32163
32216
  });
@@ -32229,11 +32282,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
32229
32282
  */
32230
32283
  runtimeState: MotionStatusSchema,
32231
32284
  /**
32232
- * Runtime-state durability: **session** — every writer of this slice
32285
+ * Runtime-state durability: **session** — the writer of this slice
32233
32286
  * writes only on an EDGE, so a restored `detected: true` would stay
32234
32287
  * frozen until the next one instead of being corrected. The next edge
32235
- * re-publishes the real state. (On who the writers are, and why there
32236
- * is more than one, see `autoClearAfterMs` above.)
32288
+ * re-publishes the real state, and the orchestrator re-publishes every
32289
+ * camera when it starts writing (D696; on who writes it, see
32290
+ * `autoClearAfterMs` above).
32237
32291
  *
32238
32292
  * See `RuntimeStateDurability`. Enforced by
32239
32293
  * `scripts/check-runtime-state-durability.ts`.
@@ -34616,8 +34670,7 @@ var ptzAutotrackCapability = {
34616
34670
  deviceNative: true,
34617
34671
  mode: "singleton",
34618
34672
  /**
34619
- * Two kinds of provider behind one name, the same shape `snapshot` and
34620
- * `doorbell` use:
34673
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
34621
34674
  *
34622
34675
  * - **Native**: the camera's own firmware autotrack, registered per device by
34623
34676
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -34625,7 +34678,7 @@ var ptzAutotrackCapability = {
34625
34678
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
34626
34679
  * which follows a subject with `ptz.move` pulses driven by the detection
34627
34680
  * pipeline. `defaultActive: false` — the operator binds it per camera in
34628
- * the bindings UI, exactly as `virtual-doorbell` is bound.
34681
+ * the bindings UI.
34629
34682
  *
34630
34683
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
34631
34684
  * one switch for the function either way. A camera never has both driving its
@@ -35300,7 +35353,7 @@ var ReadGopBytesResultSchema = object({
35300
35353
  /**
35301
35354
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
35302
35355
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
35303
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
35356
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
35304
35357
  * a replay needs several seconds of native pixels, not one frame.
35305
35358
  *
35306
35359
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -38664,6 +38717,7 @@ var zoneRulesCapability = {
38664
38717
  */
38665
38718
  durability: "restored"
38666
38719
  };
38720
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
38667
38721
  /**
38668
38722
  * Accessory device helpers — shared across drivers.
38669
38723
  *
@@ -39723,13 +39777,14 @@ var BaseDeviceProvider = class extends BaseAddon {
39723
39777
  async getStatus() {
39724
39778
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
39725
39779
  const summary = this.restoreFailureSummary();
39726
- if (summary === null) return {
39780
+ const base = {
39727
39781
  connected: true,
39728
- deviceCount: all.length
39782
+ deviceCount: all.length,
39783
+ motionSliceWriter: "orchestrator"
39729
39784
  };
39785
+ if (summary === null) return base;
39730
39786
  return {
39731
- connected: true,
39732
- deviceCount: all.length,
39787
+ ...base,
39733
39788
  error: summary
39734
39789
  };
39735
39790
  }
@@ -45165,6 +45220,12 @@ Object.freeze({
45165
45220
  addonId: null,
45166
45221
  access: "view"
45167
45222
  },
45223
+ "notificationRules.getAlarmSensors": {
45224
+ capName: "notification-rules",
45225
+ capScope: "system",
45226
+ addonId: null,
45227
+ access: "view"
45228
+ },
45168
45229
  "notificationRules.getClipRetentionAsks": {
45169
45230
  capName: "notification-rules",
45170
45231
  capScope: "system",
@@ -48743,6 +48804,11 @@ Object.freeze({
48743
48804
  }
48744
48805
  });
48745
48806
  Object.freeze({
48807
+ "accessories.getStatus": [{
48808
+ name: "deviceId",
48809
+ form: "single",
48810
+ optional: false
48811
+ }],
48746
48812
  "accessories.setChildHidden": [{
48747
48813
  name: "childDeviceId",
48748
48814
  form: "single",
@@ -48762,6 +48828,11 @@ Object.freeze({
48762
48828
  form: "single",
48763
48829
  optional: false
48764
48830
  }],
48831
+ "airQualitySensor.getStatus": [{
48832
+ name: "deviceId",
48833
+ form: "single",
48834
+ optional: false
48835
+ }],
48765
48836
  "alarmPanel.arm": [{
48766
48837
  name: "deviceId",
48767
48838
  form: "single",
@@ -48772,11 +48843,36 @@ Object.freeze({
48772
48843
  form: "single",
48773
48844
  optional: false
48774
48845
  }],
48846
+ "alarmPanel.getStatus": [{
48847
+ name: "deviceId",
48848
+ form: "single",
48849
+ optional: false
48850
+ }],
48775
48851
  "alarmPanel.trigger": [{
48776
48852
  name: "deviceId",
48777
48853
  form: "single",
48778
48854
  optional: false
48779
48855
  }],
48856
+ "ambientLightSensor.getStatus": [{
48857
+ name: "deviceId",
48858
+ form: "single",
48859
+ optional: false
48860
+ }],
48861
+ "audioAnalysis.applyDeviceSettingsPatch": [{
48862
+ name: "deviceId",
48863
+ form: "single",
48864
+ optional: false
48865
+ }],
48866
+ "audioAnalysis.getDeviceLiveContribution": [{
48867
+ name: "deviceId",
48868
+ form: "single",
48869
+ optional: false
48870
+ }],
48871
+ "audioAnalysis.getDeviceSettingsContribution": [{
48872
+ name: "deviceId",
48873
+ form: "single",
48874
+ optional: false
48875
+ }],
48780
48876
  "audioAnalysis.resolveDeviceSettings": [{
48781
48877
  name: "deviceId",
48782
48878
  form: "single",
@@ -48817,16 +48913,36 @@ Object.freeze({
48817
48913
  form: "single",
48818
48914
  optional: false
48819
48915
  }],
48916
+ "automationControl.getStatus": [{
48917
+ name: "deviceId",
48918
+ form: "single",
48919
+ optional: false
48920
+ }],
48820
48921
  "automationControl.trigger": [{
48821
48922
  name: "deviceId",
48822
48923
  form: "single",
48823
48924
  optional: false
48824
48925
  }],
48926
+ "battery.getStatus": [{
48927
+ name: "deviceId",
48928
+ form: "single",
48929
+ optional: false
48930
+ }],
48825
48931
  "battery.wakeForStream": [{
48826
48932
  name: "deviceId",
48827
48933
  form: "single",
48828
48934
  optional: false
48829
48935
  }],
48936
+ "binary.getStatus": [{
48937
+ name: "deviceId",
48938
+ form: "single",
48939
+ optional: false
48940
+ }],
48941
+ "brightness.getStatus": [{
48942
+ name: "deviceId",
48943
+ form: "single",
48944
+ optional: false
48945
+ }],
48830
48946
  "brightness.setBrightness": [{
48831
48947
  name: "deviceId",
48832
48948
  form: "single",
@@ -48842,6 +48958,26 @@ Object.freeze({
48842
48958
  form: "single",
48843
48959
  optional: false
48844
48960
  }],
48961
+ "cameraCredentials.getStatus": [{
48962
+ name: "deviceId",
48963
+ form: "single",
48964
+ optional: false
48965
+ }],
48966
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
48967
+ name: "deviceId",
48968
+ form: "single",
48969
+ optional: false
48970
+ }],
48971
+ "cameraGridLayout.getDeviceLiveContribution": [{
48972
+ name: "deviceId",
48973
+ form: "single",
48974
+ optional: false
48975
+ }],
48976
+ "cameraGridLayout.getDeviceSettingsContribution": [{
48977
+ name: "deviceId",
48978
+ form: "single",
48979
+ optional: false
48980
+ }],
48845
48981
  "cameraGridLayout.getLayout": [{
48846
48982
  name: "deviceId",
48847
48983
  form: "single",
@@ -48857,6 +48993,21 @@ Object.freeze({
48857
48993
  form: "single",
48858
48994
  optional: false
48859
48995
  }],
48996
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
48997
+ name: "deviceId",
48998
+ form: "single",
48999
+ optional: false
49000
+ }],
49001
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
49002
+ name: "deviceId",
49003
+ form: "single",
49004
+ optional: false
49005
+ }],
49006
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
49007
+ name: "deviceId",
49008
+ form: "single",
49009
+ optional: false
49010
+ }],
48860
49011
  "cameraStreams.getBrokerStreams": [{
48861
49012
  name: "deviceId",
48862
49013
  form: "single",
@@ -48882,6 +49033,16 @@ Object.freeze({
48882
49033
  form: "single",
48883
49034
  optional: false
48884
49035
  }],
49036
+ "carbonMonoxide.getStatus": [{
49037
+ name: "deviceId",
49038
+ form: "single",
49039
+ optional: false
49040
+ }],
49041
+ "climateControl.getStatus": [{
49042
+ name: "deviceId",
49043
+ form: "single",
49044
+ optional: false
49045
+ }],
48885
49046
  "climateControl.setFanMode": [{
48886
49047
  name: "deviceId",
48887
49048
  form: "single",
@@ -48922,16 +49083,41 @@ Object.freeze({
48922
49083
  form: "single",
48923
49084
  optional: false
48924
49085
  }],
49086
+ "color.getStatus": [{
49087
+ name: "deviceId",
49088
+ form: "single",
49089
+ optional: false
49090
+ }],
48925
49091
  "color.setColor": [{
48926
49092
  name: "deviceId",
48927
49093
  form: "single",
48928
49094
  optional: false
48929
49095
  }],
49096
+ "connectivity.getStatus": [{
49097
+ name: "deviceId",
49098
+ form: "single",
49099
+ optional: false
49100
+ }],
49101
+ "consumables.getStatus": [{
49102
+ name: "deviceId",
49103
+ form: "single",
49104
+ optional: false
49105
+ }],
48930
49106
  "consumables.reset": [{
48931
49107
  name: "deviceId",
48932
49108
  form: "single",
48933
49109
  optional: false
48934
49110
  }],
49111
+ "contact.getStatus": [{
49112
+ name: "deviceId",
49113
+ form: "single",
49114
+ optional: false
49115
+ }],
49116
+ "control.getStatus": [{
49117
+ name: "deviceId",
49118
+ form: "single",
49119
+ optional: false
49120
+ }],
48935
49121
  "control.setValue": [{
48936
49122
  name: "deviceId",
48937
49123
  form: "single",
@@ -48942,6 +49128,11 @@ Object.freeze({
48942
49128
  form: "single",
48943
49129
  optional: false
48944
49130
  }],
49131
+ "cover.getStatus": [{
49132
+ name: "deviceId",
49133
+ form: "single",
49134
+ optional: false
49135
+ }],
48945
49136
  "cover.open": [{
48946
49137
  name: "deviceId",
48947
49138
  form: "single",
@@ -48967,6 +49158,11 @@ Object.freeze({
48967
49158
  form: "single",
48968
49159
  optional: false
48969
49160
  }],
49161
+ "dayNight.getStatus": [{
49162
+ name: "deviceId",
49163
+ form: "single",
49164
+ optional: false
49165
+ }],
48970
49166
  "dayNight.setSettings": [{
48971
49167
  name: "deviceId",
48972
49168
  form: "single",
@@ -48977,11 +49173,31 @@ Object.freeze({
48977
49173
  form: "single",
48978
49174
  optional: true
48979
49175
  }],
49176
+ "detectionPipeline.applyDeviceSettingsPatch": [{
49177
+ name: "deviceId",
49178
+ form: "single",
49179
+ optional: false
49180
+ }],
49181
+ "detectionPipeline.getDeviceLiveContribution": [{
49182
+ name: "deviceId",
49183
+ form: "single",
49184
+ optional: false
49185
+ }],
49186
+ "detectionPipeline.getDeviceSettingsContribution": [{
49187
+ name: "deviceId",
49188
+ form: "single",
49189
+ optional: false
49190
+ }],
48980
49191
  "deviceAdminLink.getAdminLink": [{
48981
49192
  name: "deviceId",
48982
49193
  form: "single",
48983
49194
  optional: false
48984
49195
  }],
49196
+ "deviceAdoption.getStatus": [{
49197
+ name: "deviceId",
49198
+ form: "single",
49199
+ optional: false
49200
+ }],
48985
49201
  "deviceAdoption.release": [{
48986
49202
  name: "camDeviceId",
48987
49203
  form: "single",
@@ -48997,6 +49213,11 @@ Object.freeze({
48997
49213
  form: "single",
48998
49214
  optional: false
48999
49215
  }],
49216
+ "deviceDiscovery.getStatus": [{
49217
+ name: "deviceId",
49218
+ form: "single",
49219
+ optional: false
49220
+ }],
49000
49221
  "deviceDiscovery.listDiscovered": [{
49001
49222
  name: "deviceId",
49002
49223
  form: "single",
@@ -49016,6 +49237,21 @@ Object.freeze({
49016
49237
  form: "single",
49017
49238
  optional: false
49018
49239
  }],
49240
+ "deviceExport.applyDeviceSettingsPatch": [{
49241
+ name: "deviceId",
49242
+ form: "single",
49243
+ optional: false
49244
+ }],
49245
+ "deviceExport.getDeviceLiveContribution": [{
49246
+ name: "deviceId",
49247
+ form: "single",
49248
+ optional: false
49249
+ }],
49250
+ "deviceExport.getDeviceSettingsContribution": [{
49251
+ name: "deviceId",
49252
+ form: "single",
49253
+ optional: false
49254
+ }],
49019
49255
  "deviceExtension.listCandidates": [{
49020
49256
  name: "deviceId",
49021
49257
  form: "single",
@@ -49364,6 +49600,26 @@ Object.freeze({
49364
49600
  form: "single",
49365
49601
  optional: false
49366
49602
  }],
49603
+ "deviceStatus.getStatus": [{
49604
+ name: "deviceId",
49605
+ form: "single",
49606
+ optional: false
49607
+ }],
49608
+ "doorbell.getStatus": [{
49609
+ name: "deviceId",
49610
+ form: "single",
49611
+ optional: false
49612
+ }],
49613
+ "enumSensor.getStatus": [{
49614
+ name: "deviceId",
49615
+ form: "single",
49616
+ optional: false
49617
+ }],
49618
+ "eventEmitter.getStatus": [{
49619
+ name: "deviceId",
49620
+ form: "single",
49621
+ optional: false
49622
+ }],
49367
49623
  "faceGallery.getFaceByTrack": [{
49368
49624
  name: "deviceId",
49369
49625
  form: "single",
@@ -49378,6 +49634,11 @@ Object.freeze({
49378
49634
  form: "array",
49379
49635
  optional: true
49380
49636
  }],
49637
+ "fanControl.getStatus": [{
49638
+ name: "deviceId",
49639
+ form: "single",
49640
+ optional: false
49641
+ }],
49381
49642
  "fanControl.setDirection": [{
49382
49643
  name: "deviceId",
49383
49644
  form: "single",
@@ -49398,6 +49659,26 @@ Object.freeze({
49398
49659
  form: "single",
49399
49660
  optional: false
49400
49661
  }],
49662
+ "featureProbe.getStatus": [{
49663
+ name: "deviceId",
49664
+ form: "single",
49665
+ optional: false
49666
+ }],
49667
+ "flood.getStatus": [{
49668
+ name: "deviceId",
49669
+ form: "single",
49670
+ optional: false
49671
+ }],
49672
+ "gas.getStatus": [{
49673
+ name: "deviceId",
49674
+ form: "single",
49675
+ optional: false
49676
+ }],
49677
+ "humidifier.getStatus": [{
49678
+ name: "deviceId",
49679
+ form: "single",
49680
+ optional: false
49681
+ }],
49401
49682
  "humidifier.setMode": [{
49402
49683
  name: "deviceId",
49403
49684
  form: "single",
@@ -49413,11 +49694,26 @@ Object.freeze({
49413
49694
  form: "single",
49414
49695
  optional: false
49415
49696
  }],
49697
+ "humiditySensor.getStatus": [{
49698
+ name: "deviceId",
49699
+ form: "single",
49700
+ optional: false
49701
+ }],
49702
+ "image.getStatus": [{
49703
+ name: "deviceId",
49704
+ form: "single",
49705
+ optional: false
49706
+ }],
49416
49707
  "imageSettings.getOptions": [{
49417
49708
  name: "deviceId",
49418
49709
  form: "single",
49419
49710
  optional: false
49420
49711
  }],
49712
+ "imageSettings.getStatus": [{
49713
+ name: "deviceId",
49714
+ form: "single",
49715
+ optional: false
49716
+ }],
49421
49717
  "imageSettings.setSettings": [{
49422
49718
  name: "deviceId",
49423
49719
  form: "single",
@@ -49428,6 +49724,11 @@ Object.freeze({
49428
49724
  form: "single",
49429
49725
  optional: false
49430
49726
  }],
49727
+ "intercom.getStatus": [{
49728
+ name: "deviceId",
49729
+ form: "single",
49730
+ optional: false
49731
+ }],
49431
49732
  "intercom.handleAnswer": [{
49432
49733
  name: "deviceId",
49433
49734
  form: "single",
@@ -49458,6 +49759,11 @@ Object.freeze({
49458
49759
  form: "single",
49459
49760
  optional: false
49460
49761
  }],
49762
+ "lawnMowerControl.getStatus": [{
49763
+ name: "deviceId",
49764
+ form: "single",
49765
+ optional: false
49766
+ }],
49461
49767
  "lawnMowerControl.pause": [{
49462
49768
  name: "deviceId",
49463
49769
  form: "single",
@@ -49468,6 +49774,11 @@ Object.freeze({
49468
49774
  form: "single",
49469
49775
  optional: false
49470
49776
  }],
49777
+ "lockControl.getStatus": [{
49778
+ name: "deviceId",
49779
+ form: "single",
49780
+ optional: false
49781
+ }],
49471
49782
  "lockControl.lock": [{
49472
49783
  name: "deviceId",
49473
49784
  form: "single",
@@ -49483,6 +49794,11 @@ Object.freeze({
49483
49794
  form: "single",
49484
49795
  optional: false
49485
49796
  }],
49797
+ "mediaPlayer.getStatus": [{
49798
+ name: "deviceId",
49799
+ form: "single",
49800
+ optional: false
49801
+ }],
49486
49802
  "mediaPlayer.next": [{
49487
49803
  name: "deviceId",
49488
49804
  form: "single",
@@ -49543,6 +49859,11 @@ Object.freeze({
49543
49859
  form: "single",
49544
49860
  optional: false
49545
49861
  }],
49862
+ "motion.getStatus": [{
49863
+ name: "deviceId",
49864
+ form: "single",
49865
+ optional: false
49866
+ }],
49546
49867
  "motion.isDetected": [{
49547
49868
  name: "deviceId",
49548
49869
  form: "single",
@@ -49553,11 +49874,31 @@ Object.freeze({
49553
49874
  form: "single",
49554
49875
  optional: false
49555
49876
  }],
49877
+ "motionDetection.applyDeviceSettingsPatch": [{
49878
+ name: "deviceId",
49879
+ form: "single",
49880
+ optional: false
49881
+ }],
49882
+ "motionDetection.getDeviceLiveContribution": [{
49883
+ name: "deviceId",
49884
+ form: "single",
49885
+ optional: false
49886
+ }],
49887
+ "motionDetection.getDeviceSettingsContribution": [{
49888
+ name: "deviceId",
49889
+ form: "single",
49890
+ optional: false
49891
+ }],
49556
49892
  "motionDetection.removeCamera": [{
49557
49893
  name: "deviceId",
49558
49894
  form: "single",
49559
49895
  optional: false
49560
49896
  }],
49897
+ "motionTrigger.getStatus": [{
49898
+ name: "deviceId",
49899
+ form: "single",
49900
+ optional: false
49901
+ }],
49561
49902
  "motionTrigger.setMotionTrigger": [{
49562
49903
  name: "deviceId",
49563
49904
  form: "single",
@@ -49568,6 +49909,11 @@ Object.freeze({
49568
49909
  form: "single",
49569
49910
  optional: false
49570
49911
  }],
49912
+ "motionZones.getStatus": [{
49913
+ name: "deviceId",
49914
+ form: "single",
49915
+ optional: false
49916
+ }],
49571
49917
  "motionZones.setZone": [{
49572
49918
  name: "deviceId",
49573
49919
  form: "single",
@@ -49578,6 +49924,11 @@ Object.freeze({
49578
49924
  form: "single",
49579
49925
  optional: false
49580
49926
  }],
49927
+ "nativeObjectDetection.getStatus": [{
49928
+ name: "deviceId",
49929
+ form: "single",
49930
+ optional: false
49931
+ }],
49581
49932
  "nativeObjectDetection.setEnabled": [{
49582
49933
  name: "deviceId",
49583
49934
  form: "single",
@@ -49593,6 +49944,11 @@ Object.freeze({
49593
49944
  form: "single",
49594
49945
  optional: false
49595
49946
  }],
49947
+ "navigation.getStatus": [{
49948
+ name: "deviceId",
49949
+ form: "single",
49950
+ optional: false
49951
+ }],
49596
49952
  "navigation.goToPoint": [{
49597
49953
  name: "deviceId",
49598
49954
  form: "single",
@@ -49638,6 +49994,11 @@ Object.freeze({
49638
49994
  form: "single",
49639
49995
  optional: false
49640
49996
  }],
49997
+ "networkLink.getStatus": [{
49998
+ name: "deviceId",
49999
+ form: "single",
50000
+ optional: false
50001
+ }],
49641
50002
  "networkQuality.getDeviceStats": [{
49642
50003
  name: "deviceId",
49643
50004
  form: "single",
@@ -49648,6 +50009,11 @@ Object.freeze({
49648
50009
  form: "single",
49649
50010
  optional: false
49650
50011
  }],
50012
+ "notificationRules.getAlarmSensors": [{
50013
+ name: "deviceIds",
50014
+ form: "array",
50015
+ optional: false
50016
+ }],
49651
50017
  "notificationRules.setDeviceMuted": [{
49652
50018
  name: "deviceId",
49653
50019
  form: "single",
@@ -49658,11 +50024,26 @@ Object.freeze({
49658
50024
  form: "single",
49659
50025
  optional: false
49660
50026
  }],
50027
+ "notifier.getStatus": [{
50028
+ name: "deviceId",
50029
+ form: "single",
50030
+ optional: false
50031
+ }],
49661
50032
  "notifier.send": [{
49662
50033
  name: "deviceId",
49663
50034
  form: "single",
49664
50035
  optional: false
49665
50036
  }],
50037
+ "numericSensor.getStatus": [{
50038
+ name: "deviceId",
50039
+ form: "single",
50040
+ optional: false
50041
+ }],
50042
+ "osd.getStatus": [{
50043
+ name: "deviceId",
50044
+ form: "single",
50045
+ optional: false
50046
+ }],
49666
50047
  "osd.setOverlay": [{
49667
50048
  name: "deviceId",
49668
50049
  form: "single",
@@ -49722,6 +50103,11 @@ Object.freeze({
49722
50103
  form: "single",
49723
50104
  optional: false
49724
50105
  }],
50106
+ "petFeeder.getStatus": [{
50107
+ name: "deviceId",
50108
+ form: "single",
50109
+ optional: false
50110
+ }],
49725
50111
  "petFeeder.markFoodReplenished": [{
49726
50112
  name: "deviceId",
49727
50113
  form: "single",
@@ -49757,6 +50143,11 @@ Object.freeze({
49757
50143
  form: "single",
49758
50144
  optional: false
49759
50145
  }],
50146
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
50147
+ name: "deviceId",
50148
+ form: "single",
50149
+ optional: false
50150
+ }],
49760
50151
  "pipelineAnalytics.clearTrackRelation": [{
49761
50152
  name: "deviceId",
49762
50153
  form: "single",
@@ -49797,6 +50188,16 @@ Object.freeze({
49797
50188
  form: "single",
49798
50189
  optional: false
49799
50190
  }],
50191
+ "pipelineAnalytics.getDeviceLiveContribution": [{
50192
+ name: "deviceId",
50193
+ form: "single",
50194
+ optional: false
50195
+ }],
50196
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
50197
+ name: "deviceId",
50198
+ form: "single",
50199
+ optional: false
50200
+ }],
49800
50201
  "pipelineAnalytics.getEventDensity": [{
49801
50202
  name: "deviceId",
49802
50203
  form: "single",
@@ -50012,6 +50413,11 @@ Object.freeze({
50012
50413
  form: "single",
50013
50414
  optional: true
50014
50415
  }],
50416
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
50417
+ name: "deviceId",
50418
+ form: "single",
50419
+ optional: false
50420
+ }],
50015
50421
  "pipelineOrchestrator.assignAudio": [{
50016
50422
  name: "deviceId",
50017
50423
  form: "single",
@@ -50057,6 +50463,16 @@ Object.freeze({
50057
50463
  form: "single",
50058
50464
  optional: false
50059
50465
  }],
50466
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
50467
+ name: "deviceId",
50468
+ form: "single",
50469
+ optional: false
50470
+ }],
50471
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
50472
+ name: "deviceId",
50473
+ form: "single",
50474
+ optional: false
50475
+ }],
50060
50476
  "pipelineOrchestrator.getPipelineAssignment": [{
50061
50477
  name: "deviceId",
50062
50478
  form: "single",
@@ -50177,11 +50593,31 @@ Object.freeze({
50177
50593
  form: "single",
50178
50594
  optional: true
50179
50595
  }],
50596
+ "powerMeter.getStatus": [{
50597
+ name: "deviceId",
50598
+ form: "single",
50599
+ optional: false
50600
+ }],
50601
+ "presence.getStatus": [{
50602
+ name: "deviceId",
50603
+ form: "single",
50604
+ optional: false
50605
+ }],
50606
+ "pressureSensor.getStatus": [{
50607
+ name: "deviceId",
50608
+ form: "single",
50609
+ optional: false
50610
+ }],
50180
50611
  "privacyMask.getOptions": [{
50181
50612
  name: "deviceId",
50182
50613
  form: "single",
50183
50614
  optional: false
50184
50615
  }],
50616
+ "privacyMask.getStatus": [{
50617
+ name: "deviceId",
50618
+ form: "single",
50619
+ optional: false
50620
+ }],
50185
50621
  "privacyMask.setAudioEnabled": [{
50186
50622
  name: "deviceId",
50187
50623
  form: "single",
@@ -50232,6 +50668,11 @@ Object.freeze({
50232
50668
  form: "single",
50233
50669
  optional: false
50234
50670
  }],
50671
+ "ptz.getStatus": [{
50672
+ name: "deviceId",
50673
+ form: "single",
50674
+ optional: false
50675
+ }],
50235
50676
  "ptz.goHome": [{
50236
50677
  name: "deviceId",
50237
50678
  form: "single",
@@ -50322,6 +50763,11 @@ Object.freeze({
50322
50763
  form: "single",
50323
50764
  optional: false
50324
50765
  }],
50766
+ "recordingArchive.applyDeviceSettingsPatch": [{
50767
+ name: "deviceId",
50768
+ form: "single",
50769
+ optional: false
50770
+ }],
50325
50771
  "recordingArchive.deleteFootprint": [{
50326
50772
  name: "deviceId",
50327
50773
  form: "single",
@@ -50342,6 +50788,21 @@ Object.freeze({
50342
50788
  form: "single",
50343
50789
  optional: false
50344
50790
  }],
50791
+ "recordingArchive.getDeviceLiveContribution": [{
50792
+ name: "deviceId",
50793
+ form: "single",
50794
+ optional: false
50795
+ }],
50796
+ "recordingArchive.getDeviceSettingsContribution": [{
50797
+ name: "deviceId",
50798
+ form: "single",
50799
+ optional: false
50800
+ }],
50801
+ "recordingArchive.getStatus": [{
50802
+ name: "deviceId",
50803
+ form: "single",
50804
+ optional: false
50805
+ }],
50345
50806
  "recordingArchive.listOpsLog": [{
50346
50807
  name: "deviceId",
50347
50808
  form: "single",
@@ -50427,6 +50888,11 @@ Object.freeze({
50427
50888
  form: "single",
50428
50889
  optional: false
50429
50890
  }],
50891
+ "recordingOnboard.getStatus": [{
50892
+ name: "deviceId",
50893
+ form: "single",
50894
+ optional: false
50895
+ }],
50430
50896
  "recordingOnboard.setSettings": [{
50431
50897
  name: "deviceId",
50432
50898
  form: "single",
@@ -50457,6 +50923,11 @@ Object.freeze({
50457
50923
  form: "single",
50458
50924
  optional: false
50459
50925
  }],
50926
+ "sceneMonitor.getStatus": [{
50927
+ name: "deviceId",
50928
+ form: "single",
50929
+ optional: false
50930
+ }],
50460
50931
  "sceneMonitor.listScenes": [{
50461
50932
  name: "deviceId",
50462
50933
  form: "single",
@@ -50482,6 +50953,11 @@ Object.freeze({
50482
50953
  form: "single",
50483
50954
  optional: false
50484
50955
  }],
50956
+ "scriptRunner.getStatus": [{
50957
+ name: "deviceId",
50958
+ form: "single",
50959
+ optional: false
50960
+ }],
50485
50961
  "scriptRunner.run": [{
50486
50962
  name: "deviceId",
50487
50963
  form: "single",
@@ -50492,11 +50968,31 @@ Object.freeze({
50492
50968
  form: "single",
50493
50969
  optional: false
50494
50970
  }],
50971
+ "smoke.getStatus": [{
50972
+ name: "deviceId",
50973
+ form: "single",
50974
+ optional: false
50975
+ }],
50976
+ "snapshot.applyDeviceSettingsPatch": [{
50977
+ name: "deviceId",
50978
+ form: "single",
50979
+ optional: false
50980
+ }],
50495
50981
  "snapshot.getDebugState": [{
50496
50982
  name: "deviceId",
50497
50983
  form: "single",
50498
50984
  optional: false
50499
50985
  }],
50986
+ "snapshot.getDeviceLiveContribution": [{
50987
+ name: "deviceId",
50988
+ form: "single",
50989
+ optional: false
50990
+ }],
50991
+ "snapshot.getDeviceSettingsContribution": [{
50992
+ name: "deviceId",
50993
+ form: "single",
50994
+ optional: false
50995
+ }],
50500
50996
  "snapshot.getSnapshot": [{
50501
50997
  name: "deviceId",
50502
50998
  form: "single",
@@ -50513,6 +51009,11 @@ Object.freeze({
50513
51009
  form: "array",
50514
51010
  optional: false
50515
51011
  }],
51012
+ "snapshot.getStatus": [{
51013
+ name: "deviceId",
51014
+ form: "single",
51015
+ optional: false
51016
+ }],
50516
51017
  "snapshot.invalidateCache": [{
50517
51018
  name: "deviceId",
50518
51019
  form: "single",
@@ -50523,6 +51024,11 @@ Object.freeze({
50523
51024
  form: "single",
50524
51025
  optional: false
50525
51026
  }],
51027
+ "streamBroker.applyDeviceSettingsPatch": [{
51028
+ name: "deviceId",
51029
+ form: "single",
51030
+ optional: false
51031
+ }],
50526
51032
  "streamBroker.assignProfile": [{
50527
51033
  name: "deviceId",
50528
51034
  form: "single",
@@ -50538,6 +51044,16 @@ Object.freeze({
50538
51044
  form: "single",
50539
51045
  optional: false
50540
51046
  }],
51047
+ "streamBroker.getDeviceLiveContribution": [{
51048
+ name: "deviceId",
51049
+ form: "single",
51050
+ optional: false
51051
+ }],
51052
+ "streamBroker.getDeviceSettingsContribution": [{
51053
+ name: "deviceId",
51054
+ form: "single",
51055
+ optional: false
51056
+ }],
50541
51057
  "streamBroker.getStreamWithCodec": [{
50542
51058
  name: "deviceId",
50543
51059
  form: "single",
@@ -50598,16 +51114,46 @@ Object.freeze({
50598
51114
  form: "single",
50599
51115
  optional: false
50600
51116
  }],
51117
+ "streamParams.getStatus": [{
51118
+ name: "deviceId",
51119
+ form: "single",
51120
+ optional: false
51121
+ }],
50601
51122
  "streamParams.setProfile": [{
50602
51123
  name: "deviceId",
50603
51124
  form: "single",
50604
51125
  optional: false
50605
51126
  }],
51127
+ "switch.getStatus": [{
51128
+ name: "deviceId",
51129
+ form: "single",
51130
+ optional: false
51131
+ }],
50606
51132
  "switch.setState": [{
50607
51133
  name: "deviceId",
50608
51134
  form: "single",
50609
51135
  optional: false
50610
51136
  }],
51137
+ "tamper.getStatus": [{
51138
+ name: "deviceId",
51139
+ form: "single",
51140
+ optional: false
51141
+ }],
51142
+ "temperatureSensor.getStatus": [{
51143
+ name: "deviceId",
51144
+ form: "single",
51145
+ optional: false
51146
+ }],
51147
+ "update.getStatus": [{
51148
+ name: "deviceId",
51149
+ form: "single",
51150
+ optional: false
51151
+ }],
51152
+ "vacuumControl.getStatus": [{
51153
+ name: "deviceId",
51154
+ form: "single",
51155
+ optional: false
51156
+ }],
50611
51157
  "vacuumControl.locate": [{
50612
51158
  name: "deviceId",
50613
51159
  form: "single",
@@ -50643,6 +51189,11 @@ Object.freeze({
50643
51189
  form: "single",
50644
51190
  optional: false
50645
51191
  }],
51192
+ "valve.getStatus": [{
51193
+ name: "deviceId",
51194
+ form: "single",
51195
+ optional: false
51196
+ }],
50646
51197
  "valve.open": [{
50647
51198
  name: "deviceId",
50648
51199
  form: "single",
@@ -50658,6 +51209,11 @@ Object.freeze({
50658
51209
  form: "single",
50659
51210
  optional: false
50660
51211
  }],
51212
+ "vibration.getStatus": [{
51213
+ name: "deviceId",
51214
+ form: "single",
51215
+ optional: false
51216
+ }],
50661
51217
  "videoclips.dialClipStream": [{
50662
51218
  name: "deviceId",
50663
51219
  form: "single",
@@ -50693,6 +51249,11 @@ Object.freeze({
50693
51249
  form: "single",
50694
51250
  optional: false
50695
51251
  }],
51252
+ "waterHeater.getStatus": [{
51253
+ name: "deviceId",
51254
+ form: "single",
51255
+ optional: false
51256
+ }],
50696
51257
  "waterHeater.setAway": [{
50697
51258
  name: "deviceId",
50698
51259
  form: "single",
@@ -50708,6 +51269,11 @@ Object.freeze({
50708
51269
  form: "single",
50709
51270
  optional: false
50710
51271
  }],
51272
+ "weather.getStatus": [{
51273
+ name: "deviceId",
51274
+ form: "single",
51275
+ optional: false
51276
+ }],
50711
51277
  "webrtcSession.addIceCandidate": [{
50712
51278
  name: "deviceId",
50713
51279
  form: "single",
@@ -51445,7 +52011,7 @@ var PreviewTextField = string$2().max(200);
51445
52011
  * Whether the notification's preview is a STILL or a short animation.
51446
52012
  *
51447
52013
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
51448
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
52014
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
51449
52015
  * night reads better as three seconds of motion than as one frame of it. Both
51450
52016
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
51451
52017
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -51583,6 +52149,7 @@ TimelapseRuleInputSchema.extend({
51583
52149
  createdAt: number(),
51584
52150
  updatedAt: number()
51585
52151
  });
52152
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
51586
52153
  object({
51587
52154
  /**
51588
52155
  * Fraction of the box's own size added on EACH side before cutting.