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