@camstack/addon-provider-ecowitt 0.2.116 → 0.2.117

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +892 -325
  2. package/dist/addon.mjs +892 -325
  3. package/package.json +1 -3
package/dist/addon.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let http = require("http");
3
3
  let events = require("events");
4
4
  let dgram = require("dgram");
5
- //#region ../types/dist/event-category-C5xZWqz6.mjs
5
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
6
6
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
7
7
  EventCategory["SystemBoot"] = "system.boot";
8
8
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -535,6 +535,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
535
535
  */
536
536
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
537
537
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
538
+ /**
539
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
540
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
541
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
542
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
543
+ * for a camera with no attached sensor). Providers must not emit
544
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
545
+ * keeps it so (camera-grid is a named, deferred exception).
546
+ */
538
547
  EventCategory["ProviderMotion"] = "provider.motion";
539
548
  EventCategory["ProviderDetection"] = "provider.detection";
540
549
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5373,7 +5382,7 @@ var ZodIssueCode$1 = {
5373
5382
  var ZodFirstPartyTypeKind$1;
5374
5383
  ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
5375
5384
  //#endregion
5376
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5385
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5377
5386
  /**
5378
5387
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5379
5388
  * window to float samples (D455).
@@ -7416,7 +7425,7 @@ function errMsg(err) {
7416
7425
  return String(err);
7417
7426
  }
7418
7427
  //#endregion
7419
- //#region ../types/dist/composition-Dq42XWp0.mjs
7428
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
7420
7429
  /**
7421
7430
  * The ffmpeg build every CamStack node downloads, per platform and arch.
7422
7431
  *
@@ -7470,21 +7479,20 @@ function portable(target) {
7470
7479
  }
7471
7480
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
7472
7481
  /**
7473
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7474
- * valutatore puro del suo FRONTE.
7482
+ * THE table "which boolean of this device type counts as HIGH", and the
7483
+ * pure evaluator of its EDGE.
7475
7484
  *
7476
- * Viveva dentro il builtin virtual-doorbell
7477
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7478
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7479
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7480
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7481
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7482
- * SPOSTA qui e il doorbell la ri-esporta.
7485
+ * ONE table for everyone who asks "is this device HIGH?": the
7486
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
7487
+ * sensor markers, the orchestrator's camera-sensors bridge and
7488
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
7489
+ * A second copy would diverge at the first cap added, and the symptom — "the
7490
+ * sensor rings the doorbell but does not record" — is exactly D62.
7483
7491
  *
7484
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7485
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7486
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7487
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7492
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
7493
+ * two must not be unified: that one answers "what is the state WORD for a
7494
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
7495
+ * boolean's EDGE counts". Deliberately different vocabularies.
7488
7496
  */
7489
7497
  /**
7490
7498
  * Known binary / switch source caps → the boolean slice field whose
@@ -9093,22 +9101,22 @@ var CLASS_MAP_MACRO_TARGETS = [
9093
9101
  "package"
9094
9102
  ];
9095
9103
  /**
9096
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
9097
- * un operatore può selezionare.
9104
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
9105
+ * an operator can select.
9098
9106
  *
9099
- * Sono le tre offerte dallo step `object-detection`
9107
+ * They are the three offered by the `object-detection` step
9100
9108
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
9101
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
9102
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
9103
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
9104
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
9109
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
9110
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
9111
+ * `package-detection`, whose enablement is driven by zones, and offering the
9112
+ * same word twice has already made an operator turn on the COCO proxy
9105
9113
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
9106
9114
  *
9107
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
9108
- * dello step e una seconda volta come union `FirstLevelMacro`
9109
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
9110
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
9111
- * successiva.
9115
+ * ONE list. Before today the same three were hand-written in the step's offer
9116
+ * and a second time as the union `FirstLevelMacro`
9117
+ * (`types/detection.ts`); a third copy for the recording trigger
9118
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
9119
+ * invisible.
9112
9120
  */
9113
9121
  var FIRST_LEVEL_MACRO_CLASSES = [
9114
9122
  "person",
@@ -9173,17 +9181,17 @@ var RecordingStorageModeSchema = _enum([
9173
9181
  "on-device-decision"
9174
9182
  ]);
9175
9183
  /**
9176
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
9177
- * tre offerte dallo step `object-detection`, da UNA lista
9184
+ * The macro classes that can open a recording window — the same
9185
+ * three offered by the `object-detection` step, from ONE list
9178
9186
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
9179
9187
  */
9180
9188
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
9181
9189
  /**
9182
- * True quando `values` non ripete un elemento.
9190
+ * True when `values` does not repeat an element.
9183
9191
  *
9184
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
9185
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
9186
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
9192
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
9193
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
9194
+ * would count its windows twice in `segmentMissedByMs`.
9187
9195
  */
9188
9196
  var noDuplicates = (values) => new Set(values).size === values.length;
9189
9197
  /** Which detectors trigger an `events`-mode band. */
@@ -9191,34 +9199,34 @@ var RecordingTriggersSchema = object({
9191
9199
  motion: boolean().optional(),
9192
9200
  audioThresholdDbfs: number().optional(),
9193
9201
  /**
9194
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
9195
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
9196
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
9197
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
9202
+ * The macro classes whose detection opens a window. ABSENT = the source
9203
+ * is not listened to; an EMPTY array is rejected, because "events band, object
9204
+ * trigger on, no class" is the same shape "enabled and records
9205
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
9198
9206
  *
9199
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
9200
- * quelle che hanno attraversato `enabledMacroClasses`, i
9201
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
9202
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
9203
- * finestre — vedi `recorder/object-trigger.ts`.
9207
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
9208
+ * those that went through `enabledMacroClasses`, the
9209
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
9210
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
9211
+ * windows — see `recorder/object-trigger.ts`.
9204
9212
  */
9205
9213
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
9206
9214
  /**
9207
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
9208
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
9215
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
9216
+ * is not listened to; an empty array is rejected for the same reason as
9209
9217
  * `objectClasses`.
9210
9218
  *
9211
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
9212
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
9213
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
9214
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9215
- * device (D12) — mai un elenco globale di cap.
9219
+ * These are SOURCE device ids, not cameras: the band names them, so the
9220
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
9221
+ * does no RPC. The OFFER from which the operator picks them is another question, and
9222
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9223
+ * device (D12) — never a global list of caps.
9216
9224
  *
9217
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9218
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9219
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9220
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
9221
- * registrare.
9225
+ * What "high" means depends on the device TYPE and is not decided here:
9226
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
9227
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
9228
+ * the level: a contact found already open at runner restart does not
9229
+ * record.
9222
9230
  */
9223
9231
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9224
9232
  });
@@ -10295,7 +10303,7 @@ var DecoderSessionConfigSchema = object({
10295
10303
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
10296
10304
  * thing: the logging settings document on the `system` cap. Two authorities
10297
10305
  * over the values is the exact defect
10298
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
10306
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
10299
10307
  * remove; re-introducing it from the cure side would be grotesque.
10300
10308
  *
10301
10309
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -12006,7 +12014,7 @@ var BrokerStatusEnum = _enum([
12006
12014
  "unreachable",
12007
12015
  "error"
12008
12016
  ]);
12009
- var BrokerInfoSchema$1 = object({
12017
+ var BrokerInfoSchema = object({
12010
12018
  /** Stable broker id. Persisted; survives addon restarts. */
12011
12019
  id: string(),
12012
12020
  /** Addon id of the provider that OWNS this broker.
@@ -12139,7 +12147,7 @@ var GetStateInputSchema = object({
12139
12147
  * HA: entity_id (returns the cached entity state). */
12140
12148
  key: string()
12141
12149
  });
12142
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12150
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12143
12151
  kind: "mutation",
12144
12152
  auth: "admin"
12145
12153
  }), method(RemoveInputSchema, _void(), {
@@ -13850,7 +13858,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
13850
13858
  *
13851
13859
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
13852
13860
  * was wrong — corrected 2026-08-26 after the hop map
13853
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
13861
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
13854
13862
  * There is **no Zod parse at all** between the door and the engine: the
13855
13863
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
13856
13864
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -14826,7 +14834,17 @@ var SiteZoneSchema = object({
14826
14834
  var ProviderStatusSchema = object({
14827
14835
  connected: boolean(),
14828
14836
  deviceCount: number(),
14829
- error: string().optional()
14837
+ error: string().optional(),
14838
+ /**
14839
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14840
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14841
+ * which every provider bundles, so only a provider BUILT from D696-amended
14842
+ * code says it. ABSENT means an older provider that may still write it (raw
14843
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14844
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14845
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14846
+ */
14847
+ motionSliceWriter: literal("orchestrator").optional()
14830
14848
  });
14831
14849
  object({
14832
14850
  externalId: string(),
@@ -15705,109 +15723,10 @@ method(object({
15705
15723
  deviceIds: array(number()).readonly(),
15706
15724
  caps: array(string()).readonly().optional()
15707
15725
  }), record(string(), record(string(), unknown().nullable())));
15708
- /**
15709
- * Doorbell button cap. Two kinds of providers coexist behind this cap
15710
- * name (same pattern as `snapshot`):
15711
- *
15712
- * - **Native** providers: registered per-device by device-driver
15713
- * addons via `ctx.registerNativeCap` — either on a
15714
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
15715
- * or directly on the camera (Reolink registers at camera level).
15716
- * Emits an `onPressed` event every time the firmware pushes a
15717
- * ring; status tracks the last press and a pressCount since start
15718
- * (diagnostic).
15719
- *
15720
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
15721
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
15722
- * device (contact / switch / event-emitter …) into a doorbell for
15723
- * a camera. `defaultActive: false` — the operator explicitly binds
15724
- * it per camera in the device-bindings UI, then picks the source
15725
- * device + trigger in the per-device settings.
15726
- *
15727
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
15728
- * — subscribers listening at the camera level receive ring events
15729
- * with `via[]` populated. No code on the parent needed.
15730
- */
15731
- var DoorbellStatusSchema = object({
15732
- /** Ms epoch of the last press. null = never observed since this provider started. */
15733
- lastPressedAt: number().nullable(),
15734
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15735
- pressCountSinceStart: number()
15736
- });
15737
- var DoorbellPressEventSchema = object({
15738
- deviceId: number(),
15739
- timestamp: number()
15740
- });
15741
- /**
15742
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15743
- * virtual-doorbell trigger devices, exactly what the wrapper's
15744
- * `doorbellSources` persists (as `{ deviceId }` records).
15745
- */
15746
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15747
- /**
15748
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
15749
- * doorbell, owned by the `virtual-doorbell` wrapper over its
15750
- * `doorbellSources` store (D648). A source rings when one of its
15751
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
15752
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
15753
- * reports it, it never writes it.
15754
- */
15755
- var DOORBELL_SOURCE_SLOT = {
15756
- id: "doorbell-source",
15757
- label: "Doorbell trigger devices",
15758
- 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.",
15759
- shape: "association",
15760
- hostDeviceTypes: [DeviceType.Camera],
15761
- sourceCaps: SOURCE_CAPS,
15762
- cardinality: "many",
15763
- value: DoorbellSourceSlotValueSchema
15764
- };
15765
- var doorbellCapability = {
15766
- name: "doorbell",
15767
- scope: "device",
15768
- deviceNative: true,
15769
- mode: "singleton",
15770
- kind: "wrapper",
15771
- defaultActive: false,
15772
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
15773
- extensionSlots: [DOORBELL_SOURCE_SLOT],
15774
- methods: {},
15775
- events: {
15776
- /**
15777
- * Fires once per physical press. Reolink delivers via Baichuan
15778
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
15779
- * release/duration — it's a pulse.
15780
- */
15781
- onPressed: {
15782
- data: DoorbellPressEventSchema,
15783
- fromState: {
15784
- field: "lastPressedAt",
15785
- on: "advance"
15786
- }
15787
- } },
15788
- status: {
15789
- schema: DoorbellStatusSchema,
15790
- kind: "push"
15791
- },
15792
- /**
15793
- * Runtime-state slice — last press timestamp + lifetime press count.
15794
- * Mirrored by the kernel and readable via
15795
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
15796
- * without subscribing.
15797
- */
15798
- runtimeState: DoorbellStatusSchema,
15799
- /**
15800
- * 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.
15801
- *
15802
- * See `RuntimeStateDurability`. Enforced by
15803
- * `scripts/check-runtime-state-durability.ts`.
15804
- */
15805
- durability: "restored"
15806
- };
15807
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15808
- DeviceType.Camera, DeviceType.Camera;
15726
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15727
+ DeviceType.Camera;
15809
15728
  /** A slot's editable value, discriminated on `slot`. */
15810
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15729
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15811
15730
  DeviceType.Camera;
15812
15731
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15813
15732
  state: literal("unreachable"),
@@ -15844,10 +15763,11 @@ var ExtensionSlotSourceSchema = object({
15844
15763
  });
15845
15764
  /**
15846
15765
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15847
- * reported read-only, named, never written through this contract (D62). The
15848
- * virtual doorbell's sources ring only while the wrapper is bound to the
15849
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15850
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15766
+ * reported read-only, named, never written through this contract (D62) — e.g.
15767
+ * a slot whose sources act only while a wrapper is bound to the host, a
15768
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15769
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15770
+ * not be read; it is not "inactive" (D315).
15851
15771
  */
15852
15772
  var ExtensionSlotActivationSchema = object({
15853
15773
  state: _enum([
@@ -15863,7 +15783,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15863
15783
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15864
15784
  slotRef: string(),
15865
15785
  slot: ExtensionSlotIdSchema,
15866
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15786
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15867
15787
  authority: string(),
15868
15788
  activation: ExtensionSlotActivationSchema.nullable(),
15869
15789
  value: ExtensionSlotValueSchema,
@@ -16141,7 +16061,7 @@ method(object({
16141
16061
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16142
16062
  * ends in a log line, and a log line is the thing the operator asked to stop
16143
16063
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16144
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
16064
+ * 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
16145
16065
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16146
16066
  * media blackout were both diagnosed. The counters stay; this is where they can
16147
16067
  * be READ.
@@ -17517,7 +17437,7 @@ var BrokerStatusSchema$1 = _enum([
17517
17437
  "unreachable",
17518
17438
  "tls-error"
17519
17439
  ]);
17520
- var BrokerInfoSchema = object({
17440
+ var BrokerInfoSchema$1 = object({
17521
17441
  id: string(),
17522
17442
  name: string(),
17523
17443
  url: string(),
@@ -17580,7 +17500,7 @@ var StatusSchema = object({
17580
17500
  brokerCount: number(),
17581
17501
  embeddedRunning: boolean()
17582
17502
  });
17583
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17503
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17584
17504
  kind: "mutation",
17585
17505
  auth: "admin"
17586
17506
  }), method(IdInputSchema, _void(), {
@@ -19794,78 +19714,16 @@ var NcRuleInputSchema = object({
19794
19714
  */
19795
19715
  confirm: NcConfirmSchema.optional(),
19796
19716
  /**
19797
- * WAIT for face/plate recognition before saying anything.
19798
- *
19799
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
19800
- * send; the identity is neither. A face is confirmed after `confirmFrames`
19801
- * agreeing observations — p50 **11.4 s** after the track was first seen,
19802
- * measured on this hub — and an `immediate` rule enqueues on the first object
19803
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
19804
- * immediate path, and no amount of media re-resolution fixes a sentence.
19805
- *
19806
- * Only two honest answers exist, and this flag picks between them. It has
19807
- * effect ONLY on a rule that declares a recognition scope
19808
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
19809
- * other rule there is nothing to wait for and the flag is inert.
19810
- *
19811
- * | value | what happens |
19812
- * | --- | --- |
19813
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
19814
- * | 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) |
19815
- *
19816
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19817
- * on the addon cap path, and absent has to keep meaning exactly what every
19818
- * rule authored before this field meant.
19819
- *
19820
- * The cost of `true` is stated here because the editor states it too: a rule
19821
- * that waits also inherits track-close SEMANTICS — its `zones` condition
19822
- * tests every zone the track visited and a `crossing` condition can no longer
19823
- * be satisfied, because a closed track carries no crossing.
19824
- */
19825
- waitForEnhancement: boolean().optional(),
19826
- /**
19827
- * GROUP a burst of subjects into ONE notification that grows.
19828
- *
19829
- * Seconds of quiet after the last matching subject before the burst is
19830
- * considered over. While it is open, the first subject enqueues immediately —
19831
- * **exactly as today, with no added latency** — and every real growth (a new
19832
- * subject, or a name confirmed on one already in it) REPLACES that
19833
- * notification with an updated one naming everybody. The push carries the
19834
- * group's own coalescing tag, so the phone replaces rather than stacks.
19835
- *
19836
- * `0` / absent = off, and off is today's behaviour byte for byte.
19837
- *
19838
- * ### Why an idle cutoff and not a window
19839
- *
19840
- * The measured seven-person arrival on device 590 spans 110 s with every
19841
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
19842
- * idle cutoff holds it as one and ends it when the arrival actually ends.
19843
- * 30 s is a widely shipped value for the same decision.
19844
- *
19845
- * ### What it replaces
19846
- *
19847
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
19848
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
19849
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
19850
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
19851
- * A group collapses the same volume by MERGING, so the cooldown becomes a
19852
- * budget over GROUPS — which is what it always meant — and a growth is never
19853
- * throttled by the window its own first member spent.
19854
- *
19855
- * ### Interaction with {@link waitForEnhancement}
19856
- *
19857
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
19858
- * TRACK CLOSE, so with both set the group is opened by the first member to
19859
- * CLOSE — already carrying its name — and grows as later members close. That
19860
- * is later, and complete. With grouping alone the group opens on the first
19861
- * object event and picks up names as they are confirmed, through the growth
19862
- * path. Neither combination fires twice for one subject.
19863
- *
19864
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19865
- * on the addon cap path, so absent must keep meaning what it meant before this
19866
- * field existed.
19717
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
19718
+ * seconds; the rule sends ONE message when the window closes — early, once every
19719
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
19720
+ * the rule matched, with one mosaic tile per subject.
19721
+ * Absent = plain immediate (one message per track, at the first match).
19722
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
19723
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
19724
+ * path does not run Zod defaults.
19867
19725
  */
19868
- groupIdleSec: number().int().min(0).max(600).optional()
19726
+ groupingSec: number().int().min(5).max(60).optional()
19869
19727
  });
19870
19728
  /**
19871
19729
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -19913,9 +19771,10 @@ var NcRuleClearableKeySchema = _enum([
19913
19771
  "targetUsers",
19914
19772
  "snoozeOptions",
19915
19773
  "snoozeAllowGlobal",
19916
- "waitForEnhancement",
19917
19774
  "actions",
19918
19775
  "confirm",
19776
+ "groupingSec",
19777
+ "waitForEnhancement",
19919
19778
  "groupIdleSec"
19920
19779
  ]);
19921
19780
  var NcRuleUpdateInputSchema = object({
@@ -19937,9 +19796,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19937
19796
  */
19938
19797
  disabledTargetIds: array(string()).default([])
19939
19798
  });
19799
+ /**
19800
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19801
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
19802
+ * job is not an open state, and the alarm stays instant.
19803
+ */
19804
+ var NcStateSummarySectionIdSchema = _enum([
19805
+ "device-state",
19806
+ "streams",
19807
+ "battery",
19808
+ "consumables",
19809
+ "tanks",
19810
+ "detection-blind",
19811
+ "nodes",
19812
+ "addons",
19813
+ "updates"
19814
+ ]);
19940
19815
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
19941
19816
  var NcStateSummaryPreviewSectionSchema = object({
19942
- id: string(),
19817
+ id: NcStateSummarySectionIdSchema,
19943
19818
  status: _enum(["read", "unavailable"]),
19944
19819
  items: number().int().nonnegative(),
19945
19820
  reason: string().optional()
@@ -19949,7 +19824,7 @@ var NcStateSummaryPreviewSectionSchema = object({
19949
19824
  * a `rule` split (no `section`), one section's on a `section` split.
19950
19825
  */
19951
19826
  var NcStateSummaryPreviewRowSchema = object({
19952
- section: string().optional(),
19827
+ section: NcStateSummarySectionIdSchema.optional(),
19953
19828
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19954
19829
  title: string(),
19955
19830
  text: string(),
@@ -20386,6 +20261,29 @@ object({
20386
20261
  firstAt: number(),
20387
20262
  lastAt: number()
20388
20263
  });
20264
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20265
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20266
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20267
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20268
+ var NcAlarmModeDelaysListSchema = array(object({
20269
+ mode: AlarmArmModeSchema,
20270
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20271
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20272
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20273
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20274
+ var NcAlarmModeDelaysEditListSchema = array(object({
20275
+ mode: AlarmArmModeSchema,
20276
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20277
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20278
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20279
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20280
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20281
+ var NcAlarmNonBlockingEditSchema = object({
20282
+ mode: AlarmArmModeSchema,
20283
+ deviceId: number().int().positive(),
20284
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20285
+ nonBlocking: boolean()
20286
+ });
20389
20287
  /**
20390
20288
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20391
20289
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20394,10 +20292,10 @@ object({
20394
20292
  var NcAlarmNonBlockingListSchema = array(object({
20395
20293
  mode: AlarmArmModeSchema,
20396
20294
  deviceIds: array(number().int()).max(200)
20397
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20295
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20398
20296
  /**
20399
- * The three durations the panel's state machine runs on, who hears about its
20400
- * transitions, and which openings each mode tolerates.
20297
+ * The three durations — global, and per mode since D697 — the panel's state
20298
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20401
20299
  *
20402
20300
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20403
20301
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20407,15 +20305,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20407
20305
  */
20408
20306
  var NcAlarmSettingsSchema = object({
20409
20307
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20410
- exitDelaySec: number().int().min(0).max(600),
20308
+ exitDelaySec: NcAlarmDelaySecSchema,
20411
20309
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20412
- entryDelaySec: number().int().min(0).max(600),
20310
+ entryDelaySec: NcAlarmDelaySecSchema,
20413
20311
  /**
20414
20312
  * How long `triggered` lasts before the panel re-arms itself.
20415
20313
  * **0 = until an operator disarms it** — the behaviour before this field
20416
20314
  * existed, and therefore what an untouched install keeps doing.
20417
20315
  */
20418
- triggeredDurationSec: number().int().min(0).max(3600),
20316
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20419
20317
  /**
20420
20318
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20421
20319
  * remove after one release. Optional so an older admin's patch (which still
@@ -20438,17 +20336,30 @@ var NcAlarmSettingsSchema = object({
20438
20336
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20439
20337
  * parses as "every opening blocks" — the behaviour it was written under.
20440
20338
  */
20441
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20339
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20340
+ /**
20341
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20342
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20343
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20344
+ */
20345
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20442
20346
  });
20443
20347
  /**
20444
20348
  * Every field optional — a tab edits one control at a time.
20445
20349
  *
20446
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20447
- * remove an inner `.default()`, so a patch that never named the field would
20448
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20449
- * (the same trap {@link NcRulePatchSchema} documents).
20350
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20351
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20352
+ * named the field would parse to `[]` and wipe every mode's list on an
20353
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20354
+ * `modeDelays` means EDITS, not the stored overrides.
20450
20355
  */
20451
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20356
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20357
+ nonBlocking: NcAlarmNonBlockingListSchema,
20358
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20359
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20360
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20361
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20362
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20452
20363
  /**
20453
20364
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20454
20365
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20548,6 +20459,28 @@ var NcAlarmConfigSchema = object({
20548
20459
  */
20549
20460
  live: NcAlarmLiveSchema.optional()
20550
20461
  });
20462
+ var NcAlarmSensorReadingSchema = _enum([
20463
+ "open",
20464
+ "closed",
20465
+ "unknown",
20466
+ "not-opening"
20467
+ ]);
20468
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20469
+ var NcAlarmSensorStateSchema = object({
20470
+ deviceId: number().int().positive(),
20471
+ reading: NcAlarmSensorReadingSchema,
20472
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20473
+ state: string().nullable(),
20474
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20475
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20476
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20477
+ online: boolean().nullable()
20478
+ });
20479
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20480
+ var NcAlarmSensorsSchema = object({
20481
+ sensors: array(NcAlarmSensorStateSchema),
20482
+ readAt: number().int().nonnegative()
20483
+ });
20551
20484
  /**
20552
20485
  * ONE rule's demand on ONE camera's clip ring.
20553
20486
  *
@@ -20638,7 +20571,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20638
20571
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20639
20572
  kind: "mutation",
20640
20573
  auth: "admin"
20641
- });
20574
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20642
20575
  /**
20643
20576
  * Zod schemas for persisted record types.
20644
20577
  *
@@ -20985,12 +20918,26 @@ var CameraSensorRefSchema = object({
20985
20918
  function cameraSensorRefKey(ref) {
20986
20919
  return `${ref.addonId}/${ref.stableId}`;
20987
20920
  }
20988
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20989
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20990
- var CameraSensorsConfigSchema = object({
20991
- mode: CameraSensorsModeSchema,
20992
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20993
- }).superRefine((value, ctx) => {
20921
+ /**
20922
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20923
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20924
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20925
+ * camera's own motion counts only while a confirm sensor is active — with or
20926
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20927
+ */
20928
+ var CameraSensorModeSchema = _enum([
20929
+ "in-addition",
20930
+ "confirm",
20931
+ "replace"
20932
+ ]);
20933
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20934
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20935
+ /**
20936
+ * A camera's attached sensors. A CS-1 row carried an envelope
20937
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20938
+ * what the write stores (D672 rule 3), so it is never written again.
20939
+ */
20940
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20994
20941
  const seen = /* @__PURE__ */ new Set();
20995
20942
  value.sensors.forEach((ref, index) => {
20996
20943
  const key = cameraSensorRefKey(ref);
@@ -21002,39 +20949,41 @@ var CameraSensorsConfigSchema = object({
21002
20949
  seen.add(key);
21003
20950
  });
21004
20951
  });
21005
- var RefFields = {
20952
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20953
+ var AttachmentFields = {
21006
20954
  addonId: string(),
21007
- stableId: string()
20955
+ stableId: string(),
20956
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
21008
20957
  };
21009
20958
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
21010
20959
  object({
21011
- ...RefFields,
20960
+ ...AttachmentFields,
21012
20961
  state: literal("ready"),
21013
20962
  deviceId: number(),
21014
20963
  name: string(),
21015
20964
  caps: array(string()).readonly()
21016
20965
  }),
21017
20966
  object({
21018
- ...RefFields,
20967
+ ...AttachmentFields,
21019
20968
  state: literal("offline"),
21020
20969
  deviceId: number(),
21021
20970
  name: string(),
21022
20971
  reason: _enum(["offline", "disabled"])
21023
20972
  }),
21024
20973
  object({
21025
- ...RefFields,
20974
+ ...AttachmentFields,
21026
20975
  state: literal("missing"),
21027
20976
  reason: string()
21028
20977
  }),
21029
20978
  object({
21030
- ...RefFields,
20979
+ ...AttachmentFields,
21031
20980
  state: literal("unsupported"),
21032
20981
  deviceId: number(),
21033
20982
  name: string(),
21034
20983
  reason: string()
21035
20984
  }),
21036
20985
  object({
21037
- ...RefFields,
20986
+ ...AttachmentFields,
21038
20987
  state: literal("unreadable"),
21039
20988
  reason: string()
21040
20989
  })
@@ -21047,17 +20996,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
21047
20996
  * say.
21048
20997
  */
21049
20998
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20999
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
21000
+ var CameraOwnMotionSchema = _enum([
21001
+ "always",
21002
+ "when-confirmed",
21003
+ "never"
21004
+ ]);
21005
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
21006
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
21007
+ /**
21008
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
21009
+ * never the effective value. The camera's `motion` slice is the effective one,
21010
+ * so a view of the camera's own row reads this.
21011
+ * - `atMs`: when the bridge received the camera's last own edge.
21012
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
21013
+ * AND it is younger than the window the bridge counts the camera's own motion
21014
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
21015
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
21016
+ * within the window; a status read is a snapshot, so a live view re-asks.
21017
+ * Absent = this orchestrator has not received the camera's own motion since it
21018
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
21019
+ */
21020
+ var CameraRawLevelSchema = object({
21021
+ detected: boolean(),
21022
+ atMs: number()
21023
+ });
21050
21024
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
21051
- object({ state: literal("not-configured") }),
21025
+ object({
21026
+ state: literal("not-configured"),
21027
+ cameraLevel: CameraRawLevelSchema.optional()
21028
+ }),
21052
21029
  object({
21053
21030
  state: literal("unreadable"),
21054
- reason: string()
21031
+ reason: string(),
21032
+ cameraLevel: CameraRawLevelSchema.optional()
21055
21033
  }),
21056
21034
  object({
21057
21035
  state: literal("configured"),
21058
- mode: CameraSensorsModeSchema,
21036
+ cameraLevel: CameraRawLevelSchema.optional(),
21059
21037
  sensors: array(CameraSensorAttachmentSchema).readonly(),
21060
- notForwarded: CameraSensorsNotForwardedSchema.optional()
21038
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
21039
+ cameraMotion: CameraOwnMotionSchema.optional(),
21040
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
21041
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
21061
21042
  })
21062
21043
  ]);
21063
21044
  Object.freeze({
@@ -21742,14 +21723,14 @@ var TrackSchema = object({
21742
21723
  * `derive-returned-null tile=standin`,
21743
21724
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
21744
21725
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
21745
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
21726
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
21746
21727
  * tile is a face/plate stand-in, a raster crop, or an icon.
21747
21728
  *
21748
21729
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
21749
21730
  * the TILE ranked below native, so a track whose thumbnail landed natively
21750
21731
  * while its key frame missed carried no reason at all — three of the four
21751
21732
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
21752
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
21733
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
21753
21734
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
21754
21735
  * lastFrame copy source`), so its absence is now on this line whatever the
21755
21736
  * tile ended up being.
@@ -21836,7 +21817,7 @@ var MotionEventSchema = object({
21836
21817
  /**
21837
21818
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
21838
21819
  * first entry is always `0`) of every genuine off→on transition the
21839
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
21820
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
21840
21821
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
21841
21822
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
21842
21823
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -22360,6 +22341,7 @@ var KeyEventSchema = object({
22360
22341
  bestEventId: string(),
22361
22342
  /** Track lifetime in ms (lastSeen - firstSeen). */
22362
22343
  windowMs: number().optional(),
22344
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
22363
22345
  ...TrackFlagFields,
22364
22346
  ...TrackRetrainFields
22365
22347
  });
@@ -24288,8 +24270,10 @@ var RunnerCameraConfigSchema = object({
24288
24270
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24289
24271
  * analyzer providers) running on decoded frames in this runner.
24290
24272
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24291
- * analytics). The provider emits ProviderMotion
24292
- * events; the orchestrator forwards to `reportMotion`.
24273
+ * analytics). The provider emits its raw push as `ProviderMotion`
24274
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24275
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24276
+ * `reportMotion`.
24293
24277
  */
24294
24278
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24295
24279
  /**
@@ -24466,7 +24450,15 @@ var RunnerLocalLoadSchema = object({
24466
24450
  hasGpu: boolean(),
24467
24451
  inferenceBackend: string().optional(),
24468
24452
  cpuCores: number().optional()
24469
- })
24453
+ }),
24454
+ /**
24455
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24456
+ * runner never writes it. ABSENT = a runner older than D696, which still
24457
+ * writes the slice from its phase machine; the orchestrator does not write
24458
+ * while any runner node is absent-or-unanswered, so one slice never has two
24459
+ * writers.
24460
+ */
24461
+ motionSliceWriter: literal("orchestrator").optional()
24470
24462
  });
24471
24463
  /**
24472
24464
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -27131,7 +27123,7 @@ var ClipPlaybackSchema = object({
27131
27123
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
27132
27124
  * time the camera is awake for its own reasons — is deliberately not a member:
27133
27125
  * it was proposed, it is free on the battery, and the operator declined it on
27134
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
27126
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
27135
27127
  * D558 "Considered and not taken").
27136
27128
  */
27137
27129
  var ClipWakeSchema = _enum(["authorised"]);
@@ -27392,7 +27384,7 @@ DeviceType.Camera, method(object({
27392
27384
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
27393
27385
  * assumed the answer was a fan-out over everything a camera has. The
27394
27386
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
27395
- * solo"* — so the list is asked of one provider at a time and there is
27387
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
27396
27388
  * nothing to filter out of it.
27397
27389
  */
27398
27390
  provider: string().min(1)
@@ -29987,6 +29979,70 @@ onStatusChanged: { data: object({
29987
29979
  * whether persisting is worth a SQLite commit. */
29988
29980
  volatileStateFields: ["lastChangedAt"]
29989
29981
  };
29982
+ var DoorbellStatusSchema = object({
29983
+ /** Ms epoch of the last press. null = never observed since this provider started. */
29984
+ lastPressedAt: number().nullable(),
29985
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
29986
+ pressCountSinceStart: number()
29987
+ });
29988
+ var DoorbellPressEventSchema = object({
29989
+ deviceId: number(),
29990
+ timestamp: number()
29991
+ });
29992
+ /**
29993
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
29994
+ * they are the same cap:
29995
+ *
29996
+ * - **Native** providers, registered per device by a driver addon through
29997
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
29998
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
29999
+ * camera level). They emit `onPressed` on every firmware ring.
30000
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
30001
+ * the cap, its `lastPressedAt` rising from the sources the operator
30002
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
30003
+ * from that field's advance (`fromState`).
30004
+ *
30005
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
30006
+ */
30007
+ var doorbellCapability = {
30008
+ name: "doorbell",
30009
+ scope: "device",
30010
+ deviceNative: true,
30011
+ mode: "singleton",
30012
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
30013
+ methods: {},
30014
+ events: {
30015
+ /**
30016
+ * Fires once per physical press. Reolink delivers via Baichuan
30017
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
30018
+ * release/duration — it's a pulse.
30019
+ */
30020
+ onPressed: {
30021
+ data: DoorbellPressEventSchema,
30022
+ fromState: {
30023
+ field: "lastPressedAt",
30024
+ on: "advance"
30025
+ }
30026
+ } },
30027
+ status: {
30028
+ schema: DoorbellStatusSchema,
30029
+ kind: "push"
30030
+ },
30031
+ /**
30032
+ * Runtime-state slice — last press timestamp + lifetime press count.
30033
+ * Mirrored by the kernel and readable via
30034
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
30035
+ * without subscribing.
30036
+ */
30037
+ runtimeState: DoorbellStatusSchema,
30038
+ /**
30039
+ * 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.
30040
+ *
30041
+ * See `RuntimeStateDurability`. Enforced by
30042
+ * `scripts/check-runtime-state-durability.ts`.
30043
+ */
30044
+ durability: "restored"
30045
+ };
29990
30046
  /**
29991
30047
  * Enum-state sensor — a string value picked from a finite option set.
29992
30048
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -32131,9 +32187,9 @@ var MotionStatusSchema = object({
32131
32187
  /** Ms epoch of the last detected-true observation. Null if never detected. */
32132
32188
  lastDetectedAt: number().nullable(),
32133
32189
  /**
32134
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
32135
- * `null` while false and on every `Sensor` device (D475) — see that
32136
- * constant's doc for the one-authority rule.
32190
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
32191
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
32192
+ * device (D475) — see that constant's doc for the one-authority rule.
32137
32193
  *
32138
32194
  * ## Reading this field still arms nothing
32139
32195
  *
@@ -32151,34 +32207,31 @@ var MotionStatusSchema = object({
32151
32207
  * `addon-export-alexa/src/motion-clear-hold.ts` and
32152
32208
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
32153
32209
  *
32154
- * ## Who writes it
32155
- *
32156
- * - **Cameras** — the runner's phase machine, `active → watching` on
32157
- * `cooldown_expired`, which then writes this slice with
32158
- * `detected: false` (`handlePhaseChanged` in
32159
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
32160
- * matters most for the sources that only ever push a rising one:
32161
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
32162
- * a false.
32163
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
32164
- * provider pushes the false itself, from the upstream system's own
32165
- * state change. No phase machine is involved.
32166
- *
32167
- * ### The phase machine is CANONICAL, not sole — and that is a defect
32168
- *
32169
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
32170
- * phase machine is the sole writer for a camera. It is not.
32171
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
32172
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
32173
- * Hikvision's comment says why: it read THIS docblock, agreed the
32174
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
32175
- * two authorities can disagree about one slice, which this repo
32176
- * forbids, and the doc said otherwise — which is worse than saying
32177
- * nothing, because it reads as verification.
32178
- *
32179
- * This predates D475 and is not fixed there: the fix touches every
32180
- * camera provider. Recorded in D475's Consequences. Do not restore the
32181
- * "sole writer" wording without also removing the other writers.
32210
+ * ## Who writes it (D696)
32211
+ *
32212
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
32213
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
32214
+ * `camera-sensors/motion-slice.ts`), alongside the effective
32215
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
32216
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
32217
+ * device activity, as the camera's `motionSources` counts them. A source
32218
+ * that never sends a clear falls one window after its last `true`.
32219
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
32220
+ * writes this slice (not even a boot seed), and neither does the runner's
32221
+ * phase machine: its phase is "a session is attached" for every on-motion
32222
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
32223
+ * A provider's `isDetected` answers from the hub's slice.
32224
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32225
+ * imports) — the provider pushes both edges itself, from the upstream
32226
+ * system's own state change. That is the sensor's own fact.
32227
+ *
32228
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
32229
+ * `motion` slice; each sensor writer is a named exemption.
32230
+ *
32231
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
32232
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
32233
+ * it, every provider seeded it at boot, and every session left it
32234
+ * `detected: true` after its detach.
32182
32235
  */
32183
32236
  autoClearAfterMs: number().nullable()
32184
32237
  });
@@ -32250,11 +32303,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
32250
32303
  */
32251
32304
  runtimeState: MotionStatusSchema,
32252
32305
  /**
32253
- * Runtime-state durability: **session** — every writer of this slice
32306
+ * Runtime-state durability: **session** — the writer of this slice
32254
32307
  * writes only on an EDGE, so a restored `detected: true` would stay
32255
32308
  * frozen until the next one instead of being corrected. The next edge
32256
- * re-publishes the real state. (On who the writers are, and why there
32257
- * is more than one, see `autoClearAfterMs` above.)
32309
+ * re-publishes the real state, and the orchestrator re-publishes every
32310
+ * camera when it starts writing (D696; on who writes it, see
32311
+ * `autoClearAfterMs` above).
32258
32312
  *
32259
32313
  * See `RuntimeStateDurability`. Enforced by
32260
32314
  * `scripts/check-runtime-state-durability.ts`.
@@ -34637,8 +34691,7 @@ var ptzAutotrackCapability = {
34637
34691
  deviceNative: true,
34638
34692
  mode: "singleton",
34639
34693
  /**
34640
- * Two kinds of provider behind one name, the same shape `snapshot` and
34641
- * `doorbell` use:
34694
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
34642
34695
  *
34643
34696
  * - **Native**: the camera's own firmware autotrack, registered per device by
34644
34697
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -34646,7 +34699,7 @@ var ptzAutotrackCapability = {
34646
34699
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
34647
34700
  * which follows a subject with `ptz.move` pulses driven by the detection
34648
34701
  * pipeline. `defaultActive: false` — the operator binds it per camera in
34649
- * the bindings UI, exactly as `virtual-doorbell` is bound.
34702
+ * the bindings UI.
34650
34703
  *
34651
34704
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
34652
34705
  * one switch for the function either way. A camera never has both driving its
@@ -35321,7 +35374,7 @@ var ReadGopBytesResultSchema = object({
35321
35374
  /**
35322
35375
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
35323
35376
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
35324
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
35377
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
35325
35378
  * a replay needs several seconds of native pixels, not one frame.
35326
35379
  *
35327
35380
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -38685,6 +38738,7 @@ var zoneRulesCapability = {
38685
38738
  */
38686
38739
  durability: "restored"
38687
38740
  };
38741
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
38688
38742
  /**
38689
38743
  * Accessory device helpers — shared across drivers.
38690
38744
  *
@@ -39744,13 +39798,14 @@ var BaseDeviceProvider = class extends BaseAddon {
39744
39798
  async getStatus() {
39745
39799
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
39746
39800
  const summary = this.restoreFailureSummary();
39747
- if (summary === null) return {
39801
+ const base = {
39748
39802
  connected: true,
39749
- deviceCount: all.length
39803
+ deviceCount: all.length,
39804
+ motionSliceWriter: "orchestrator"
39750
39805
  };
39806
+ if (summary === null) return base;
39751
39807
  return {
39752
- connected: true,
39753
- deviceCount: all.length,
39808
+ ...base,
39754
39809
  error: summary
39755
39810
  };
39756
39811
  }
@@ -45186,6 +45241,12 @@ Object.freeze({
45186
45241
  addonId: null,
45187
45242
  access: "view"
45188
45243
  },
45244
+ "notificationRules.getAlarmSensors": {
45245
+ capName: "notification-rules",
45246
+ capScope: "system",
45247
+ addonId: null,
45248
+ access: "view"
45249
+ },
45189
45250
  "notificationRules.getClipRetentionAsks": {
45190
45251
  capName: "notification-rules",
45191
45252
  capScope: "system",
@@ -48764,6 +48825,11 @@ Object.freeze({
48764
48825
  }
48765
48826
  });
48766
48827
  Object.freeze({
48828
+ "accessories.getStatus": [{
48829
+ name: "deviceId",
48830
+ form: "single",
48831
+ optional: false
48832
+ }],
48767
48833
  "accessories.setChildHidden": [{
48768
48834
  name: "childDeviceId",
48769
48835
  form: "single",
@@ -48783,6 +48849,11 @@ Object.freeze({
48783
48849
  form: "single",
48784
48850
  optional: false
48785
48851
  }],
48852
+ "airQualitySensor.getStatus": [{
48853
+ name: "deviceId",
48854
+ form: "single",
48855
+ optional: false
48856
+ }],
48786
48857
  "alarmPanel.arm": [{
48787
48858
  name: "deviceId",
48788
48859
  form: "single",
@@ -48793,11 +48864,36 @@ Object.freeze({
48793
48864
  form: "single",
48794
48865
  optional: false
48795
48866
  }],
48867
+ "alarmPanel.getStatus": [{
48868
+ name: "deviceId",
48869
+ form: "single",
48870
+ optional: false
48871
+ }],
48796
48872
  "alarmPanel.trigger": [{
48797
48873
  name: "deviceId",
48798
48874
  form: "single",
48799
48875
  optional: false
48800
48876
  }],
48877
+ "ambientLightSensor.getStatus": [{
48878
+ name: "deviceId",
48879
+ form: "single",
48880
+ optional: false
48881
+ }],
48882
+ "audioAnalysis.applyDeviceSettingsPatch": [{
48883
+ name: "deviceId",
48884
+ form: "single",
48885
+ optional: false
48886
+ }],
48887
+ "audioAnalysis.getDeviceLiveContribution": [{
48888
+ name: "deviceId",
48889
+ form: "single",
48890
+ optional: false
48891
+ }],
48892
+ "audioAnalysis.getDeviceSettingsContribution": [{
48893
+ name: "deviceId",
48894
+ form: "single",
48895
+ optional: false
48896
+ }],
48801
48897
  "audioAnalysis.resolveDeviceSettings": [{
48802
48898
  name: "deviceId",
48803
48899
  form: "single",
@@ -48838,16 +48934,36 @@ Object.freeze({
48838
48934
  form: "single",
48839
48935
  optional: false
48840
48936
  }],
48937
+ "automationControl.getStatus": [{
48938
+ name: "deviceId",
48939
+ form: "single",
48940
+ optional: false
48941
+ }],
48841
48942
  "automationControl.trigger": [{
48842
48943
  name: "deviceId",
48843
48944
  form: "single",
48844
48945
  optional: false
48845
48946
  }],
48947
+ "battery.getStatus": [{
48948
+ name: "deviceId",
48949
+ form: "single",
48950
+ optional: false
48951
+ }],
48846
48952
  "battery.wakeForStream": [{
48847
48953
  name: "deviceId",
48848
48954
  form: "single",
48849
48955
  optional: false
48850
48956
  }],
48957
+ "binary.getStatus": [{
48958
+ name: "deviceId",
48959
+ form: "single",
48960
+ optional: false
48961
+ }],
48962
+ "brightness.getStatus": [{
48963
+ name: "deviceId",
48964
+ form: "single",
48965
+ optional: false
48966
+ }],
48851
48967
  "brightness.setBrightness": [{
48852
48968
  name: "deviceId",
48853
48969
  form: "single",
@@ -48863,6 +48979,26 @@ Object.freeze({
48863
48979
  form: "single",
48864
48980
  optional: false
48865
48981
  }],
48982
+ "cameraCredentials.getStatus": [{
48983
+ name: "deviceId",
48984
+ form: "single",
48985
+ optional: false
48986
+ }],
48987
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
48988
+ name: "deviceId",
48989
+ form: "single",
48990
+ optional: false
48991
+ }],
48992
+ "cameraGridLayout.getDeviceLiveContribution": [{
48993
+ name: "deviceId",
48994
+ form: "single",
48995
+ optional: false
48996
+ }],
48997
+ "cameraGridLayout.getDeviceSettingsContribution": [{
48998
+ name: "deviceId",
48999
+ form: "single",
49000
+ optional: false
49001
+ }],
48866
49002
  "cameraGridLayout.getLayout": [{
48867
49003
  name: "deviceId",
48868
49004
  form: "single",
@@ -48878,6 +49014,21 @@ Object.freeze({
48878
49014
  form: "single",
48879
49015
  optional: false
48880
49016
  }],
49017
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
49018
+ name: "deviceId",
49019
+ form: "single",
49020
+ optional: false
49021
+ }],
49022
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
49023
+ name: "deviceId",
49024
+ form: "single",
49025
+ optional: false
49026
+ }],
49027
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
49028
+ name: "deviceId",
49029
+ form: "single",
49030
+ optional: false
49031
+ }],
48881
49032
  "cameraStreams.getBrokerStreams": [{
48882
49033
  name: "deviceId",
48883
49034
  form: "single",
@@ -48903,6 +49054,16 @@ Object.freeze({
48903
49054
  form: "single",
48904
49055
  optional: false
48905
49056
  }],
49057
+ "carbonMonoxide.getStatus": [{
49058
+ name: "deviceId",
49059
+ form: "single",
49060
+ optional: false
49061
+ }],
49062
+ "climateControl.getStatus": [{
49063
+ name: "deviceId",
49064
+ form: "single",
49065
+ optional: false
49066
+ }],
48906
49067
  "climateControl.setFanMode": [{
48907
49068
  name: "deviceId",
48908
49069
  form: "single",
@@ -48943,16 +49104,41 @@ Object.freeze({
48943
49104
  form: "single",
48944
49105
  optional: false
48945
49106
  }],
49107
+ "color.getStatus": [{
49108
+ name: "deviceId",
49109
+ form: "single",
49110
+ optional: false
49111
+ }],
48946
49112
  "color.setColor": [{
48947
49113
  name: "deviceId",
48948
49114
  form: "single",
48949
49115
  optional: false
48950
49116
  }],
49117
+ "connectivity.getStatus": [{
49118
+ name: "deviceId",
49119
+ form: "single",
49120
+ optional: false
49121
+ }],
49122
+ "consumables.getStatus": [{
49123
+ name: "deviceId",
49124
+ form: "single",
49125
+ optional: false
49126
+ }],
48951
49127
  "consumables.reset": [{
48952
49128
  name: "deviceId",
48953
49129
  form: "single",
48954
49130
  optional: false
48955
49131
  }],
49132
+ "contact.getStatus": [{
49133
+ name: "deviceId",
49134
+ form: "single",
49135
+ optional: false
49136
+ }],
49137
+ "control.getStatus": [{
49138
+ name: "deviceId",
49139
+ form: "single",
49140
+ optional: false
49141
+ }],
48956
49142
  "control.setValue": [{
48957
49143
  name: "deviceId",
48958
49144
  form: "single",
@@ -48963,6 +49149,11 @@ Object.freeze({
48963
49149
  form: "single",
48964
49150
  optional: false
48965
49151
  }],
49152
+ "cover.getStatus": [{
49153
+ name: "deviceId",
49154
+ form: "single",
49155
+ optional: false
49156
+ }],
48966
49157
  "cover.open": [{
48967
49158
  name: "deviceId",
48968
49159
  form: "single",
@@ -48988,6 +49179,11 @@ Object.freeze({
48988
49179
  form: "single",
48989
49180
  optional: false
48990
49181
  }],
49182
+ "dayNight.getStatus": [{
49183
+ name: "deviceId",
49184
+ form: "single",
49185
+ optional: false
49186
+ }],
48991
49187
  "dayNight.setSettings": [{
48992
49188
  name: "deviceId",
48993
49189
  form: "single",
@@ -48998,11 +49194,31 @@ Object.freeze({
48998
49194
  form: "single",
48999
49195
  optional: true
49000
49196
  }],
49197
+ "detectionPipeline.applyDeviceSettingsPatch": [{
49198
+ name: "deviceId",
49199
+ form: "single",
49200
+ optional: false
49201
+ }],
49202
+ "detectionPipeline.getDeviceLiveContribution": [{
49203
+ name: "deviceId",
49204
+ form: "single",
49205
+ optional: false
49206
+ }],
49207
+ "detectionPipeline.getDeviceSettingsContribution": [{
49208
+ name: "deviceId",
49209
+ form: "single",
49210
+ optional: false
49211
+ }],
49001
49212
  "deviceAdminLink.getAdminLink": [{
49002
49213
  name: "deviceId",
49003
49214
  form: "single",
49004
49215
  optional: false
49005
49216
  }],
49217
+ "deviceAdoption.getStatus": [{
49218
+ name: "deviceId",
49219
+ form: "single",
49220
+ optional: false
49221
+ }],
49006
49222
  "deviceAdoption.release": [{
49007
49223
  name: "camDeviceId",
49008
49224
  form: "single",
@@ -49018,6 +49234,11 @@ Object.freeze({
49018
49234
  form: "single",
49019
49235
  optional: false
49020
49236
  }],
49237
+ "deviceDiscovery.getStatus": [{
49238
+ name: "deviceId",
49239
+ form: "single",
49240
+ optional: false
49241
+ }],
49021
49242
  "deviceDiscovery.listDiscovered": [{
49022
49243
  name: "deviceId",
49023
49244
  form: "single",
@@ -49037,6 +49258,21 @@ Object.freeze({
49037
49258
  form: "single",
49038
49259
  optional: false
49039
49260
  }],
49261
+ "deviceExport.applyDeviceSettingsPatch": [{
49262
+ name: "deviceId",
49263
+ form: "single",
49264
+ optional: false
49265
+ }],
49266
+ "deviceExport.getDeviceLiveContribution": [{
49267
+ name: "deviceId",
49268
+ form: "single",
49269
+ optional: false
49270
+ }],
49271
+ "deviceExport.getDeviceSettingsContribution": [{
49272
+ name: "deviceId",
49273
+ form: "single",
49274
+ optional: false
49275
+ }],
49040
49276
  "deviceExtension.listCandidates": [{
49041
49277
  name: "deviceId",
49042
49278
  form: "single",
@@ -49385,6 +49621,26 @@ Object.freeze({
49385
49621
  form: "single",
49386
49622
  optional: false
49387
49623
  }],
49624
+ "deviceStatus.getStatus": [{
49625
+ name: "deviceId",
49626
+ form: "single",
49627
+ optional: false
49628
+ }],
49629
+ "doorbell.getStatus": [{
49630
+ name: "deviceId",
49631
+ form: "single",
49632
+ optional: false
49633
+ }],
49634
+ "enumSensor.getStatus": [{
49635
+ name: "deviceId",
49636
+ form: "single",
49637
+ optional: false
49638
+ }],
49639
+ "eventEmitter.getStatus": [{
49640
+ name: "deviceId",
49641
+ form: "single",
49642
+ optional: false
49643
+ }],
49388
49644
  "faceGallery.getFaceByTrack": [{
49389
49645
  name: "deviceId",
49390
49646
  form: "single",
@@ -49399,6 +49655,11 @@ Object.freeze({
49399
49655
  form: "array",
49400
49656
  optional: true
49401
49657
  }],
49658
+ "fanControl.getStatus": [{
49659
+ name: "deviceId",
49660
+ form: "single",
49661
+ optional: false
49662
+ }],
49402
49663
  "fanControl.setDirection": [{
49403
49664
  name: "deviceId",
49404
49665
  form: "single",
@@ -49419,6 +49680,26 @@ Object.freeze({
49419
49680
  form: "single",
49420
49681
  optional: false
49421
49682
  }],
49683
+ "featureProbe.getStatus": [{
49684
+ name: "deviceId",
49685
+ form: "single",
49686
+ optional: false
49687
+ }],
49688
+ "flood.getStatus": [{
49689
+ name: "deviceId",
49690
+ form: "single",
49691
+ optional: false
49692
+ }],
49693
+ "gas.getStatus": [{
49694
+ name: "deviceId",
49695
+ form: "single",
49696
+ optional: false
49697
+ }],
49698
+ "humidifier.getStatus": [{
49699
+ name: "deviceId",
49700
+ form: "single",
49701
+ optional: false
49702
+ }],
49422
49703
  "humidifier.setMode": [{
49423
49704
  name: "deviceId",
49424
49705
  form: "single",
@@ -49434,11 +49715,26 @@ Object.freeze({
49434
49715
  form: "single",
49435
49716
  optional: false
49436
49717
  }],
49718
+ "humiditySensor.getStatus": [{
49719
+ name: "deviceId",
49720
+ form: "single",
49721
+ optional: false
49722
+ }],
49723
+ "image.getStatus": [{
49724
+ name: "deviceId",
49725
+ form: "single",
49726
+ optional: false
49727
+ }],
49437
49728
  "imageSettings.getOptions": [{
49438
49729
  name: "deviceId",
49439
49730
  form: "single",
49440
49731
  optional: false
49441
49732
  }],
49733
+ "imageSettings.getStatus": [{
49734
+ name: "deviceId",
49735
+ form: "single",
49736
+ optional: false
49737
+ }],
49442
49738
  "imageSettings.setSettings": [{
49443
49739
  name: "deviceId",
49444
49740
  form: "single",
@@ -49449,6 +49745,11 @@ Object.freeze({
49449
49745
  form: "single",
49450
49746
  optional: false
49451
49747
  }],
49748
+ "intercom.getStatus": [{
49749
+ name: "deviceId",
49750
+ form: "single",
49751
+ optional: false
49752
+ }],
49452
49753
  "intercom.handleAnswer": [{
49453
49754
  name: "deviceId",
49454
49755
  form: "single",
@@ -49479,6 +49780,11 @@ Object.freeze({
49479
49780
  form: "single",
49480
49781
  optional: false
49481
49782
  }],
49783
+ "lawnMowerControl.getStatus": [{
49784
+ name: "deviceId",
49785
+ form: "single",
49786
+ optional: false
49787
+ }],
49482
49788
  "lawnMowerControl.pause": [{
49483
49789
  name: "deviceId",
49484
49790
  form: "single",
@@ -49489,6 +49795,11 @@ Object.freeze({
49489
49795
  form: "single",
49490
49796
  optional: false
49491
49797
  }],
49798
+ "lockControl.getStatus": [{
49799
+ name: "deviceId",
49800
+ form: "single",
49801
+ optional: false
49802
+ }],
49492
49803
  "lockControl.lock": [{
49493
49804
  name: "deviceId",
49494
49805
  form: "single",
@@ -49504,6 +49815,11 @@ Object.freeze({
49504
49815
  form: "single",
49505
49816
  optional: false
49506
49817
  }],
49818
+ "mediaPlayer.getStatus": [{
49819
+ name: "deviceId",
49820
+ form: "single",
49821
+ optional: false
49822
+ }],
49507
49823
  "mediaPlayer.next": [{
49508
49824
  name: "deviceId",
49509
49825
  form: "single",
@@ -49564,6 +49880,11 @@ Object.freeze({
49564
49880
  form: "single",
49565
49881
  optional: false
49566
49882
  }],
49883
+ "motion.getStatus": [{
49884
+ name: "deviceId",
49885
+ form: "single",
49886
+ optional: false
49887
+ }],
49567
49888
  "motion.isDetected": [{
49568
49889
  name: "deviceId",
49569
49890
  form: "single",
@@ -49574,11 +49895,31 @@ Object.freeze({
49574
49895
  form: "single",
49575
49896
  optional: false
49576
49897
  }],
49898
+ "motionDetection.applyDeviceSettingsPatch": [{
49899
+ name: "deviceId",
49900
+ form: "single",
49901
+ optional: false
49902
+ }],
49903
+ "motionDetection.getDeviceLiveContribution": [{
49904
+ name: "deviceId",
49905
+ form: "single",
49906
+ optional: false
49907
+ }],
49908
+ "motionDetection.getDeviceSettingsContribution": [{
49909
+ name: "deviceId",
49910
+ form: "single",
49911
+ optional: false
49912
+ }],
49577
49913
  "motionDetection.removeCamera": [{
49578
49914
  name: "deviceId",
49579
49915
  form: "single",
49580
49916
  optional: false
49581
49917
  }],
49918
+ "motionTrigger.getStatus": [{
49919
+ name: "deviceId",
49920
+ form: "single",
49921
+ optional: false
49922
+ }],
49582
49923
  "motionTrigger.setMotionTrigger": [{
49583
49924
  name: "deviceId",
49584
49925
  form: "single",
@@ -49589,6 +49930,11 @@ Object.freeze({
49589
49930
  form: "single",
49590
49931
  optional: false
49591
49932
  }],
49933
+ "motionZones.getStatus": [{
49934
+ name: "deviceId",
49935
+ form: "single",
49936
+ optional: false
49937
+ }],
49592
49938
  "motionZones.setZone": [{
49593
49939
  name: "deviceId",
49594
49940
  form: "single",
@@ -49599,6 +49945,11 @@ Object.freeze({
49599
49945
  form: "single",
49600
49946
  optional: false
49601
49947
  }],
49948
+ "nativeObjectDetection.getStatus": [{
49949
+ name: "deviceId",
49950
+ form: "single",
49951
+ optional: false
49952
+ }],
49602
49953
  "nativeObjectDetection.setEnabled": [{
49603
49954
  name: "deviceId",
49604
49955
  form: "single",
@@ -49614,6 +49965,11 @@ Object.freeze({
49614
49965
  form: "single",
49615
49966
  optional: false
49616
49967
  }],
49968
+ "navigation.getStatus": [{
49969
+ name: "deviceId",
49970
+ form: "single",
49971
+ optional: false
49972
+ }],
49617
49973
  "navigation.goToPoint": [{
49618
49974
  name: "deviceId",
49619
49975
  form: "single",
@@ -49659,6 +50015,11 @@ Object.freeze({
49659
50015
  form: "single",
49660
50016
  optional: false
49661
50017
  }],
50018
+ "networkLink.getStatus": [{
50019
+ name: "deviceId",
50020
+ form: "single",
50021
+ optional: false
50022
+ }],
49662
50023
  "networkQuality.getDeviceStats": [{
49663
50024
  name: "deviceId",
49664
50025
  form: "single",
@@ -49669,6 +50030,11 @@ Object.freeze({
49669
50030
  form: "single",
49670
50031
  optional: false
49671
50032
  }],
50033
+ "notificationRules.getAlarmSensors": [{
50034
+ name: "deviceIds",
50035
+ form: "array",
50036
+ optional: false
50037
+ }],
49672
50038
  "notificationRules.setDeviceMuted": [{
49673
50039
  name: "deviceId",
49674
50040
  form: "single",
@@ -49679,11 +50045,26 @@ Object.freeze({
49679
50045
  form: "single",
49680
50046
  optional: false
49681
50047
  }],
50048
+ "notifier.getStatus": [{
50049
+ name: "deviceId",
50050
+ form: "single",
50051
+ optional: false
50052
+ }],
49682
50053
  "notifier.send": [{
49683
50054
  name: "deviceId",
49684
50055
  form: "single",
49685
50056
  optional: false
49686
50057
  }],
50058
+ "numericSensor.getStatus": [{
50059
+ name: "deviceId",
50060
+ form: "single",
50061
+ optional: false
50062
+ }],
50063
+ "osd.getStatus": [{
50064
+ name: "deviceId",
50065
+ form: "single",
50066
+ optional: false
50067
+ }],
49687
50068
  "osd.setOverlay": [{
49688
50069
  name: "deviceId",
49689
50070
  form: "single",
@@ -49743,6 +50124,11 @@ Object.freeze({
49743
50124
  form: "single",
49744
50125
  optional: false
49745
50126
  }],
50127
+ "petFeeder.getStatus": [{
50128
+ name: "deviceId",
50129
+ form: "single",
50130
+ optional: false
50131
+ }],
49746
50132
  "petFeeder.markFoodReplenished": [{
49747
50133
  name: "deviceId",
49748
50134
  form: "single",
@@ -49778,6 +50164,11 @@ Object.freeze({
49778
50164
  form: "single",
49779
50165
  optional: false
49780
50166
  }],
50167
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
50168
+ name: "deviceId",
50169
+ form: "single",
50170
+ optional: false
50171
+ }],
49781
50172
  "pipelineAnalytics.clearTrackRelation": [{
49782
50173
  name: "deviceId",
49783
50174
  form: "single",
@@ -49818,6 +50209,16 @@ Object.freeze({
49818
50209
  form: "single",
49819
50210
  optional: false
49820
50211
  }],
50212
+ "pipelineAnalytics.getDeviceLiveContribution": [{
50213
+ name: "deviceId",
50214
+ form: "single",
50215
+ optional: false
50216
+ }],
50217
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
50218
+ name: "deviceId",
50219
+ form: "single",
50220
+ optional: false
50221
+ }],
49821
50222
  "pipelineAnalytics.getEventDensity": [{
49822
50223
  name: "deviceId",
49823
50224
  form: "single",
@@ -50033,6 +50434,11 @@ Object.freeze({
50033
50434
  form: "single",
50034
50435
  optional: true
50035
50436
  }],
50437
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
50438
+ name: "deviceId",
50439
+ form: "single",
50440
+ optional: false
50441
+ }],
50036
50442
  "pipelineOrchestrator.assignAudio": [{
50037
50443
  name: "deviceId",
50038
50444
  form: "single",
@@ -50078,6 +50484,16 @@ Object.freeze({
50078
50484
  form: "single",
50079
50485
  optional: false
50080
50486
  }],
50487
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
50488
+ name: "deviceId",
50489
+ form: "single",
50490
+ optional: false
50491
+ }],
50492
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
50493
+ name: "deviceId",
50494
+ form: "single",
50495
+ optional: false
50496
+ }],
50081
50497
  "pipelineOrchestrator.getPipelineAssignment": [{
50082
50498
  name: "deviceId",
50083
50499
  form: "single",
@@ -50198,11 +50614,31 @@ Object.freeze({
50198
50614
  form: "single",
50199
50615
  optional: true
50200
50616
  }],
50617
+ "powerMeter.getStatus": [{
50618
+ name: "deviceId",
50619
+ form: "single",
50620
+ optional: false
50621
+ }],
50622
+ "presence.getStatus": [{
50623
+ name: "deviceId",
50624
+ form: "single",
50625
+ optional: false
50626
+ }],
50627
+ "pressureSensor.getStatus": [{
50628
+ name: "deviceId",
50629
+ form: "single",
50630
+ optional: false
50631
+ }],
50201
50632
  "privacyMask.getOptions": [{
50202
50633
  name: "deviceId",
50203
50634
  form: "single",
50204
50635
  optional: false
50205
50636
  }],
50637
+ "privacyMask.getStatus": [{
50638
+ name: "deviceId",
50639
+ form: "single",
50640
+ optional: false
50641
+ }],
50206
50642
  "privacyMask.setAudioEnabled": [{
50207
50643
  name: "deviceId",
50208
50644
  form: "single",
@@ -50253,6 +50689,11 @@ Object.freeze({
50253
50689
  form: "single",
50254
50690
  optional: false
50255
50691
  }],
50692
+ "ptz.getStatus": [{
50693
+ name: "deviceId",
50694
+ form: "single",
50695
+ optional: false
50696
+ }],
50256
50697
  "ptz.goHome": [{
50257
50698
  name: "deviceId",
50258
50699
  form: "single",
@@ -50343,6 +50784,11 @@ Object.freeze({
50343
50784
  form: "single",
50344
50785
  optional: false
50345
50786
  }],
50787
+ "recordingArchive.applyDeviceSettingsPatch": [{
50788
+ name: "deviceId",
50789
+ form: "single",
50790
+ optional: false
50791
+ }],
50346
50792
  "recordingArchive.deleteFootprint": [{
50347
50793
  name: "deviceId",
50348
50794
  form: "single",
@@ -50363,6 +50809,21 @@ Object.freeze({
50363
50809
  form: "single",
50364
50810
  optional: false
50365
50811
  }],
50812
+ "recordingArchive.getDeviceLiveContribution": [{
50813
+ name: "deviceId",
50814
+ form: "single",
50815
+ optional: false
50816
+ }],
50817
+ "recordingArchive.getDeviceSettingsContribution": [{
50818
+ name: "deviceId",
50819
+ form: "single",
50820
+ optional: false
50821
+ }],
50822
+ "recordingArchive.getStatus": [{
50823
+ name: "deviceId",
50824
+ form: "single",
50825
+ optional: false
50826
+ }],
50366
50827
  "recordingArchive.listOpsLog": [{
50367
50828
  name: "deviceId",
50368
50829
  form: "single",
@@ -50448,6 +50909,11 @@ Object.freeze({
50448
50909
  form: "single",
50449
50910
  optional: false
50450
50911
  }],
50912
+ "recordingOnboard.getStatus": [{
50913
+ name: "deviceId",
50914
+ form: "single",
50915
+ optional: false
50916
+ }],
50451
50917
  "recordingOnboard.setSettings": [{
50452
50918
  name: "deviceId",
50453
50919
  form: "single",
@@ -50478,6 +50944,11 @@ Object.freeze({
50478
50944
  form: "single",
50479
50945
  optional: false
50480
50946
  }],
50947
+ "sceneMonitor.getStatus": [{
50948
+ name: "deviceId",
50949
+ form: "single",
50950
+ optional: false
50951
+ }],
50481
50952
  "sceneMonitor.listScenes": [{
50482
50953
  name: "deviceId",
50483
50954
  form: "single",
@@ -50503,6 +50974,11 @@ Object.freeze({
50503
50974
  form: "single",
50504
50975
  optional: false
50505
50976
  }],
50977
+ "scriptRunner.getStatus": [{
50978
+ name: "deviceId",
50979
+ form: "single",
50980
+ optional: false
50981
+ }],
50506
50982
  "scriptRunner.run": [{
50507
50983
  name: "deviceId",
50508
50984
  form: "single",
@@ -50513,11 +50989,31 @@ Object.freeze({
50513
50989
  form: "single",
50514
50990
  optional: false
50515
50991
  }],
50992
+ "smoke.getStatus": [{
50993
+ name: "deviceId",
50994
+ form: "single",
50995
+ optional: false
50996
+ }],
50997
+ "snapshot.applyDeviceSettingsPatch": [{
50998
+ name: "deviceId",
50999
+ form: "single",
51000
+ optional: false
51001
+ }],
50516
51002
  "snapshot.getDebugState": [{
50517
51003
  name: "deviceId",
50518
51004
  form: "single",
50519
51005
  optional: false
50520
51006
  }],
51007
+ "snapshot.getDeviceLiveContribution": [{
51008
+ name: "deviceId",
51009
+ form: "single",
51010
+ optional: false
51011
+ }],
51012
+ "snapshot.getDeviceSettingsContribution": [{
51013
+ name: "deviceId",
51014
+ form: "single",
51015
+ optional: false
51016
+ }],
50521
51017
  "snapshot.getSnapshot": [{
50522
51018
  name: "deviceId",
50523
51019
  form: "single",
@@ -50534,6 +51030,11 @@ Object.freeze({
50534
51030
  form: "array",
50535
51031
  optional: false
50536
51032
  }],
51033
+ "snapshot.getStatus": [{
51034
+ name: "deviceId",
51035
+ form: "single",
51036
+ optional: false
51037
+ }],
50537
51038
  "snapshot.invalidateCache": [{
50538
51039
  name: "deviceId",
50539
51040
  form: "single",
@@ -50544,6 +51045,11 @@ Object.freeze({
50544
51045
  form: "single",
50545
51046
  optional: false
50546
51047
  }],
51048
+ "streamBroker.applyDeviceSettingsPatch": [{
51049
+ name: "deviceId",
51050
+ form: "single",
51051
+ optional: false
51052
+ }],
50547
51053
  "streamBroker.assignProfile": [{
50548
51054
  name: "deviceId",
50549
51055
  form: "single",
@@ -50559,6 +51065,16 @@ Object.freeze({
50559
51065
  form: "single",
50560
51066
  optional: false
50561
51067
  }],
51068
+ "streamBroker.getDeviceLiveContribution": [{
51069
+ name: "deviceId",
51070
+ form: "single",
51071
+ optional: false
51072
+ }],
51073
+ "streamBroker.getDeviceSettingsContribution": [{
51074
+ name: "deviceId",
51075
+ form: "single",
51076
+ optional: false
51077
+ }],
50562
51078
  "streamBroker.getStreamWithCodec": [{
50563
51079
  name: "deviceId",
50564
51080
  form: "single",
@@ -50619,16 +51135,46 @@ Object.freeze({
50619
51135
  form: "single",
50620
51136
  optional: false
50621
51137
  }],
51138
+ "streamParams.getStatus": [{
51139
+ name: "deviceId",
51140
+ form: "single",
51141
+ optional: false
51142
+ }],
50622
51143
  "streamParams.setProfile": [{
50623
51144
  name: "deviceId",
50624
51145
  form: "single",
50625
51146
  optional: false
50626
51147
  }],
51148
+ "switch.getStatus": [{
51149
+ name: "deviceId",
51150
+ form: "single",
51151
+ optional: false
51152
+ }],
50627
51153
  "switch.setState": [{
50628
51154
  name: "deviceId",
50629
51155
  form: "single",
50630
51156
  optional: false
50631
51157
  }],
51158
+ "tamper.getStatus": [{
51159
+ name: "deviceId",
51160
+ form: "single",
51161
+ optional: false
51162
+ }],
51163
+ "temperatureSensor.getStatus": [{
51164
+ name: "deviceId",
51165
+ form: "single",
51166
+ optional: false
51167
+ }],
51168
+ "update.getStatus": [{
51169
+ name: "deviceId",
51170
+ form: "single",
51171
+ optional: false
51172
+ }],
51173
+ "vacuumControl.getStatus": [{
51174
+ name: "deviceId",
51175
+ form: "single",
51176
+ optional: false
51177
+ }],
50632
51178
  "vacuumControl.locate": [{
50633
51179
  name: "deviceId",
50634
51180
  form: "single",
@@ -50664,6 +51210,11 @@ Object.freeze({
50664
51210
  form: "single",
50665
51211
  optional: false
50666
51212
  }],
51213
+ "valve.getStatus": [{
51214
+ name: "deviceId",
51215
+ form: "single",
51216
+ optional: false
51217
+ }],
50667
51218
  "valve.open": [{
50668
51219
  name: "deviceId",
50669
51220
  form: "single",
@@ -50679,6 +51230,11 @@ Object.freeze({
50679
51230
  form: "single",
50680
51231
  optional: false
50681
51232
  }],
51233
+ "vibration.getStatus": [{
51234
+ name: "deviceId",
51235
+ form: "single",
51236
+ optional: false
51237
+ }],
50682
51238
  "videoclips.dialClipStream": [{
50683
51239
  name: "deviceId",
50684
51240
  form: "single",
@@ -50714,6 +51270,11 @@ Object.freeze({
50714
51270
  form: "single",
50715
51271
  optional: false
50716
51272
  }],
51273
+ "waterHeater.getStatus": [{
51274
+ name: "deviceId",
51275
+ form: "single",
51276
+ optional: false
51277
+ }],
50717
51278
  "waterHeater.setAway": [{
50718
51279
  name: "deviceId",
50719
51280
  form: "single",
@@ -50729,6 +51290,11 @@ Object.freeze({
50729
51290
  form: "single",
50730
51291
  optional: false
50731
51292
  }],
51293
+ "weather.getStatus": [{
51294
+ name: "deviceId",
51295
+ form: "single",
51296
+ optional: false
51297
+ }],
50732
51298
  "webrtcSession.addIceCandidate": [{
50733
51299
  name: "deviceId",
50734
51300
  form: "single",
@@ -51466,7 +52032,7 @@ var PreviewTextField = string().max(200);
51466
52032
  * Whether the notification's preview is a STILL or a short animation.
51467
52033
  *
51468
52034
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
51469
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
52035
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
51470
52036
  * night reads better as three seconds of motion than as one frame of it. Both
51471
52037
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
51472
52038
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -51604,6 +52170,7 @@ TimelapseRuleInputSchema.extend({
51604
52170
  createdAt: number(),
51605
52171
  updatedAt: number()
51606
52172
  });
52173
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
51607
52174
  object({
51608
52175
  /**
51609
52176
  * Fraction of the box's own size added on EACH side before cutting.