@camstack/addon-provider-gree 0.2.115 → 0.2.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +892 -325
  2. package/dist/addon.mjs +892 -325
  3. package/package.json +1 -3
package/dist/addon.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createSocket } from "dgram";
2
2
  import { createCipheriv, createDecipheriv } from "crypto";
3
3
  import { EventEmitter } from "events";
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 = {
5372
5381
  var ZodFirstPartyTypeKind;
5373
5382
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
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.
@@ -14712,7 +14720,17 @@ var SiteZoneSchema = object({
14712
14720
  var ProviderStatusSchema = object({
14713
14721
  connected: boolean(),
14714
14722
  deviceCount: number(),
14715
- error: string().optional()
14723
+ error: string().optional(),
14724
+ /**
14725
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14726
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14727
+ * which every provider bundles, so only a provider BUILT from D696-amended
14728
+ * code says it. ABSENT means an older provider that may still write it (raw
14729
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14730
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14731
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14732
+ */
14733
+ motionSliceWriter: literal("orchestrator").optional()
14716
14734
  });
14717
14735
  object({
14718
14736
  externalId: string(),
@@ -15591,109 +15609,10 @@ method(object({
15591
15609
  deviceIds: array(number()).readonly(),
15592
15610
  caps: array(string()).readonly().optional()
15593
15611
  }), record(string(), record(string(), unknown().nullable())));
15594
- /**
15595
- * Doorbell button cap. Two kinds of providers coexist behind this cap
15596
- * name (same pattern as `snapshot`):
15597
- *
15598
- * - **Native** providers: registered per-device by device-driver
15599
- * addons via `ctx.registerNativeCap` — either on a
15600
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
15601
- * or directly on the camera (Reolink registers at camera level).
15602
- * Emits an `onPressed` event every time the firmware pushes a
15603
- * ring; status tracks the last press and a pressCount since start
15604
- * (diagnostic).
15605
- *
15606
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
15607
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
15608
- * device (contact / switch / event-emitter …) into a doorbell for
15609
- * a camera. `defaultActive: false` — the operator explicitly binds
15610
- * it per camera in the device-bindings UI, then picks the source
15611
- * device + trigger in the per-device settings.
15612
- *
15613
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
15614
- * — subscribers listening at the camera level receive ring events
15615
- * with `via[]` populated. No code on the parent needed.
15616
- */
15617
- var DoorbellStatusSchema = object({
15618
- /** Ms epoch of the last press. null = never observed since this provider started. */
15619
- lastPressedAt: number().nullable(),
15620
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15621
- pressCountSinceStart: number()
15622
- });
15623
- var DoorbellPressEventSchema = object({
15624
- deviceId: number(),
15625
- timestamp: number()
15626
- });
15627
- /**
15628
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15629
- * virtual-doorbell trigger devices, exactly what the wrapper's
15630
- * `doorbellSources` persists (as `{ deviceId }` records).
15631
- */
15632
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15633
- /**
15634
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
15635
- * doorbell, owned by the `virtual-doorbell` wrapper over its
15636
- * `doorbellSources` store (D648). A source rings when one of its
15637
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
15638
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
15639
- * reports it, it never writes it.
15640
- */
15641
- var DOORBELL_SOURCE_SLOT = {
15642
- id: "doorbell-source",
15643
- label: "Doorbell trigger devices",
15644
- 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.",
15645
- shape: "association",
15646
- hostDeviceTypes: [DeviceType.Camera],
15647
- sourceCaps: SOURCE_CAPS,
15648
- cardinality: "many",
15649
- value: DoorbellSourceSlotValueSchema
15650
- };
15651
- var doorbellCapability = {
15652
- name: "doorbell",
15653
- scope: "device",
15654
- deviceNative: true,
15655
- mode: "singleton",
15656
- kind: "wrapper",
15657
- defaultActive: false,
15658
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
15659
- extensionSlots: [DOORBELL_SOURCE_SLOT],
15660
- methods: {},
15661
- events: {
15662
- /**
15663
- * Fires once per physical press. Reolink delivers via Baichuan
15664
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
15665
- * release/duration — it's a pulse.
15666
- */
15667
- onPressed: {
15668
- data: DoorbellPressEventSchema,
15669
- fromState: {
15670
- field: "lastPressedAt",
15671
- on: "advance"
15672
- }
15673
- } },
15674
- status: {
15675
- schema: DoorbellStatusSchema,
15676
- kind: "push"
15677
- },
15678
- /**
15679
- * Runtime-state slice — last press timestamp + lifetime press count.
15680
- * Mirrored by the kernel and readable via
15681
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
15682
- * without subscribing.
15683
- */
15684
- runtimeState: DoorbellStatusSchema,
15685
- /**
15686
- * 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.
15687
- *
15688
- * See `RuntimeStateDurability`. Enforced by
15689
- * `scripts/check-runtime-state-durability.ts`.
15690
- */
15691
- durability: "restored"
15692
- };
15693
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15694
- DeviceType.Camera, DeviceType.Camera;
15612
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15613
+ DeviceType.Camera;
15695
15614
  /** A slot's editable value, discriminated on `slot`. */
15696
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15615
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15697
15616
  DeviceType.Camera;
15698
15617
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15699
15618
  state: literal("unreachable"),
@@ -15730,10 +15649,11 @@ var ExtensionSlotSourceSchema = object({
15730
15649
  });
15731
15650
  /**
15732
15651
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15733
- * reported read-only, named, never written through this contract (D62). The
15734
- * virtual doorbell's sources ring only while the wrapper is bound to the
15735
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15736
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15652
+ * reported read-only, named, never written through this contract (D62) — e.g.
15653
+ * a slot whose sources act only while a wrapper is bound to the host, a
15654
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15655
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15656
+ * not be read; it is not "inactive" (D315).
15737
15657
  */
15738
15658
  var ExtensionSlotActivationSchema = object({
15739
15659
  state: _enum([
@@ -15749,7 +15669,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15749
15669
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15750
15670
  slotRef: string(),
15751
15671
  slot: ExtensionSlotIdSchema,
15752
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15672
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15753
15673
  authority: string(),
15754
15674
  activation: ExtensionSlotActivationSchema.nullable(),
15755
15675
  value: ExtensionSlotValueSchema,
@@ -16027,7 +15947,7 @@ method(object({
16027
15947
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16028
15948
  * ends in a log line, and a log line is the thing the operator asked to stop
16029
15949
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16030
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
15950
+ * 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
16031
15951
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16032
15952
  * media blackout were both diagnosed. The counters stay; this is where they can
16033
15953
  * be READ.
@@ -17403,7 +17323,7 @@ var BrokerStatusSchema$1 = _enum([
17403
17323
  "unreachable",
17404
17324
  "tls-error"
17405
17325
  ]);
17406
- var BrokerInfoSchema = object({
17326
+ var BrokerInfoSchema$1 = object({
17407
17327
  id: string(),
17408
17328
  name: string(),
17409
17329
  url: string(),
@@ -17466,7 +17386,7 @@ var StatusSchema = object({
17466
17386
  brokerCount: number(),
17467
17387
  embeddedRunning: boolean()
17468
17388
  });
17469
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17389
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17470
17390
  kind: "mutation",
17471
17391
  auth: "admin"
17472
17392
  }), method(IdInputSchema, _void(), {
@@ -19680,78 +19600,16 @@ var NcRuleInputSchema = object({
19680
19600
  */
19681
19601
  confirm: NcConfirmSchema.optional(),
19682
19602
  /**
19683
- * WAIT for face/plate recognition before saying anything.
19684
- *
19685
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
19686
- * send; the identity is neither. A face is confirmed after `confirmFrames`
19687
- * agreeing observations — p50 **11.4 s** after the track was first seen,
19688
- * measured on this hub — and an `immediate` rule enqueues on the first object
19689
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
19690
- * immediate path, and no amount of media re-resolution fixes a sentence.
19691
- *
19692
- * Only two honest answers exist, and this flag picks between them. It has
19693
- * effect ONLY on a rule that declares a recognition scope
19694
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
19695
- * other rule there is nothing to wait for and the flag is inert.
19696
- *
19697
- * | value | what happens |
19698
- * | --- | --- |
19699
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
19700
- * | 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) |
19701
- *
19702
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19703
- * on the addon cap path, and absent has to keep meaning exactly what every
19704
- * rule authored before this field meant.
19705
- *
19706
- * The cost of `true` is stated here because the editor states it too: a rule
19707
- * that waits also inherits track-close SEMANTICS — its `zones` condition
19708
- * tests every zone the track visited and a `crossing` condition can no longer
19709
- * be satisfied, because a closed track carries no crossing.
19603
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
19604
+ * seconds; the rule sends ONE message when the window closes — early, once every
19605
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
19606
+ * the rule matched, with one mosaic tile per subject.
19607
+ * Absent = plain immediate (one message per track, at the first match).
19608
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
19609
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
19610
+ * path does not run Zod defaults.
19710
19611
  */
19711
- waitForEnhancement: boolean().optional(),
19712
- /**
19713
- * GROUP a burst of subjects into ONE notification that grows.
19714
- *
19715
- * Seconds of quiet after the last matching subject before the burst is
19716
- * considered over. While it is open, the first subject enqueues immediately —
19717
- * **exactly as today, with no added latency** — and every real growth (a new
19718
- * subject, or a name confirmed on one already in it) REPLACES that
19719
- * notification with an updated one naming everybody. The push carries the
19720
- * group's own coalescing tag, so the phone replaces rather than stacks.
19721
- *
19722
- * `0` / absent = off, and off is today's behaviour byte for byte.
19723
- *
19724
- * ### Why an idle cutoff and not a window
19725
- *
19726
- * The measured seven-person arrival on device 590 spans 110 s with every
19727
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
19728
- * idle cutoff holds it as one and ends it when the arrival actually ends.
19729
- * 30 s is a widely shipped value for the same decision.
19730
- *
19731
- * ### What it replaces
19732
- *
19733
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
19734
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
19735
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
19736
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
19737
- * A group collapses the same volume by MERGING, so the cooldown becomes a
19738
- * budget over GROUPS — which is what it always meant — and a growth is never
19739
- * throttled by the window its own first member spent.
19740
- *
19741
- * ### Interaction with {@link waitForEnhancement}
19742
- *
19743
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
19744
- * TRACK CLOSE, so with both set the group is opened by the first member to
19745
- * CLOSE — already carrying its name — and grows as later members close. That
19746
- * is later, and complete. With grouping alone the group opens on the first
19747
- * object event and picks up names as they are confirmed, through the growth
19748
- * path. Neither combination fires twice for one subject.
19749
- *
19750
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19751
- * on the addon cap path, so absent must keep meaning what it meant before this
19752
- * field existed.
19753
- */
19754
- groupIdleSec: number().int().min(0).max(600).optional()
19612
+ groupingSec: number().int().min(5).max(60).optional()
19755
19613
  });
19756
19614
  /**
19757
19615
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -19799,9 +19657,10 @@ var NcRuleClearableKeySchema = _enum([
19799
19657
  "targetUsers",
19800
19658
  "snoozeOptions",
19801
19659
  "snoozeAllowGlobal",
19802
- "waitForEnhancement",
19803
19660
  "actions",
19804
19661
  "confirm",
19662
+ "groupingSec",
19663
+ "waitForEnhancement",
19805
19664
  "groupIdleSec"
19806
19665
  ]);
19807
19666
  var NcRuleUpdateInputSchema = object({
@@ -19823,9 +19682,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19823
19682
  */
19824
19683
  disabledTargetIds: array(string()).default([])
19825
19684
  });
19685
+ /**
19686
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19687
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
19688
+ * job is not an open state, and the alarm stays instant.
19689
+ */
19690
+ var NcStateSummarySectionIdSchema = _enum([
19691
+ "device-state",
19692
+ "streams",
19693
+ "battery",
19694
+ "consumables",
19695
+ "tanks",
19696
+ "detection-blind",
19697
+ "nodes",
19698
+ "addons",
19699
+ "updates"
19700
+ ]);
19826
19701
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
19827
19702
  var NcStateSummaryPreviewSectionSchema = object({
19828
- id: string(),
19703
+ id: NcStateSummarySectionIdSchema,
19829
19704
  status: _enum(["read", "unavailable"]),
19830
19705
  items: number().int().nonnegative(),
19831
19706
  reason: string().optional()
@@ -19835,7 +19710,7 @@ var NcStateSummaryPreviewSectionSchema = object({
19835
19710
  * a `rule` split (no `section`), one section's on a `section` split.
19836
19711
  */
19837
19712
  var NcStateSummaryPreviewRowSchema = object({
19838
- section: string().optional(),
19713
+ section: NcStateSummarySectionIdSchema.optional(),
19839
19714
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19840
19715
  title: string(),
19841
19716
  text: string(),
@@ -20272,6 +20147,29 @@ object({
20272
20147
  firstAt: number(),
20273
20148
  lastAt: number()
20274
20149
  });
20150
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20151
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20152
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20153
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20154
+ var NcAlarmModeDelaysListSchema = array(object({
20155
+ mode: AlarmArmModeSchema,
20156
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20157
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20158
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20159
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20160
+ var NcAlarmModeDelaysEditListSchema = array(object({
20161
+ mode: AlarmArmModeSchema,
20162
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20163
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20164
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20165
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20166
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20167
+ var NcAlarmNonBlockingEditSchema = object({
20168
+ mode: AlarmArmModeSchema,
20169
+ deviceId: number().int().positive(),
20170
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20171
+ nonBlocking: boolean()
20172
+ });
20275
20173
  /**
20276
20174
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20277
20175
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20280,10 +20178,10 @@ object({
20280
20178
  var NcAlarmNonBlockingListSchema = array(object({
20281
20179
  mode: AlarmArmModeSchema,
20282
20180
  deviceIds: array(number().int()).max(200)
20283
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20181
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20284
20182
  /**
20285
- * The three durations the panel's state machine runs on, who hears about its
20286
- * transitions, and which openings each mode tolerates.
20183
+ * The three durations — global, and per mode since D697 — the panel's state
20184
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20287
20185
  *
20288
20186
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20289
20187
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20293,15 +20191,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20293
20191
  */
20294
20192
  var NcAlarmSettingsSchema = object({
20295
20193
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20296
- exitDelaySec: number().int().min(0).max(600),
20194
+ exitDelaySec: NcAlarmDelaySecSchema,
20297
20195
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20298
- entryDelaySec: number().int().min(0).max(600),
20196
+ entryDelaySec: NcAlarmDelaySecSchema,
20299
20197
  /**
20300
20198
  * How long `triggered` lasts before the panel re-arms itself.
20301
20199
  * **0 = until an operator disarms it** — the behaviour before this field
20302
20200
  * existed, and therefore what an untouched install keeps doing.
20303
20201
  */
20304
- triggeredDurationSec: number().int().min(0).max(3600),
20202
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20305
20203
  /**
20306
20204
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20307
20205
  * remove after one release. Optional so an older admin's patch (which still
@@ -20324,17 +20222,30 @@ var NcAlarmSettingsSchema = object({
20324
20222
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20325
20223
  * parses as "every opening blocks" — the behaviour it was written under.
20326
20224
  */
20327
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20225
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20226
+ /**
20227
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20228
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20229
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20230
+ */
20231
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20328
20232
  });
20329
20233
  /**
20330
20234
  * Every field optional — a tab edits one control at a time.
20331
20235
  *
20332
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20333
- * remove an inner `.default()`, so a patch that never named the field would
20334
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20335
- * (the same trap {@link NcRulePatchSchema} documents).
20236
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20237
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20238
+ * named the field would parse to `[]` and wipe every mode's list on an
20239
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20240
+ * `modeDelays` means EDITS, not the stored overrides.
20336
20241
  */
20337
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20242
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20243
+ nonBlocking: NcAlarmNonBlockingListSchema,
20244
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20245
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20246
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20247
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20248
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20338
20249
  /**
20339
20250
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20340
20251
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20434,6 +20345,28 @@ var NcAlarmConfigSchema = object({
20434
20345
  */
20435
20346
  live: NcAlarmLiveSchema.optional()
20436
20347
  });
20348
+ var NcAlarmSensorReadingSchema = _enum([
20349
+ "open",
20350
+ "closed",
20351
+ "unknown",
20352
+ "not-opening"
20353
+ ]);
20354
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20355
+ var NcAlarmSensorStateSchema = object({
20356
+ deviceId: number().int().positive(),
20357
+ reading: NcAlarmSensorReadingSchema,
20358
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20359
+ state: string().nullable(),
20360
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20361
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20362
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20363
+ online: boolean().nullable()
20364
+ });
20365
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20366
+ var NcAlarmSensorsSchema = object({
20367
+ sensors: array(NcAlarmSensorStateSchema),
20368
+ readAt: number().int().nonnegative()
20369
+ });
20437
20370
  /**
20438
20371
  * ONE rule's demand on ONE camera's clip ring.
20439
20372
  *
@@ -20524,7 +20457,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20524
20457
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20525
20458
  kind: "mutation",
20526
20459
  auth: "admin"
20527
- });
20460
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20528
20461
  /**
20529
20462
  * Zod schemas for persisted record types.
20530
20463
  *
@@ -20871,12 +20804,26 @@ var CameraSensorRefSchema = object({
20871
20804
  function cameraSensorRefKey(ref) {
20872
20805
  return `${ref.addonId}/${ref.stableId}`;
20873
20806
  }
20874
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20875
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20876
- var CameraSensorsConfigSchema = object({
20877
- mode: CameraSensorsModeSchema,
20878
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20879
- }).superRefine((value, ctx) => {
20807
+ /**
20808
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20809
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20810
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20811
+ * camera's own motion counts only while a confirm sensor is active — with or
20812
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20813
+ */
20814
+ var CameraSensorModeSchema = _enum([
20815
+ "in-addition",
20816
+ "confirm",
20817
+ "replace"
20818
+ ]);
20819
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20820
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20821
+ /**
20822
+ * A camera's attached sensors. A CS-1 row carried an envelope
20823
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20824
+ * what the write stores (D672 rule 3), so it is never written again.
20825
+ */
20826
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20880
20827
  const seen = /* @__PURE__ */ new Set();
20881
20828
  value.sensors.forEach((ref, index) => {
20882
20829
  const key = cameraSensorRefKey(ref);
@@ -20888,39 +20835,41 @@ var CameraSensorsConfigSchema = object({
20888
20835
  seen.add(key);
20889
20836
  });
20890
20837
  });
20891
- var RefFields = {
20838
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20839
+ var AttachmentFields = {
20892
20840
  addonId: string(),
20893
- stableId: string()
20841
+ stableId: string(),
20842
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20894
20843
  };
20895
20844
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20896
20845
  object({
20897
- ...RefFields,
20846
+ ...AttachmentFields,
20898
20847
  state: literal("ready"),
20899
20848
  deviceId: number(),
20900
20849
  name: string(),
20901
20850
  caps: array(string()).readonly()
20902
20851
  }),
20903
20852
  object({
20904
- ...RefFields,
20853
+ ...AttachmentFields,
20905
20854
  state: literal("offline"),
20906
20855
  deviceId: number(),
20907
20856
  name: string(),
20908
20857
  reason: _enum(["offline", "disabled"])
20909
20858
  }),
20910
20859
  object({
20911
- ...RefFields,
20860
+ ...AttachmentFields,
20912
20861
  state: literal("missing"),
20913
20862
  reason: string()
20914
20863
  }),
20915
20864
  object({
20916
- ...RefFields,
20865
+ ...AttachmentFields,
20917
20866
  state: literal("unsupported"),
20918
20867
  deviceId: number(),
20919
20868
  name: string(),
20920
20869
  reason: string()
20921
20870
  }),
20922
20871
  object({
20923
- ...RefFields,
20872
+ ...AttachmentFields,
20924
20873
  state: literal("unreadable"),
20925
20874
  reason: string()
20926
20875
  })
@@ -20933,17 +20882,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20933
20882
  * say.
20934
20883
  */
20935
20884
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20885
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20886
+ var CameraOwnMotionSchema = _enum([
20887
+ "always",
20888
+ "when-confirmed",
20889
+ "never"
20890
+ ]);
20891
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20892
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20893
+ /**
20894
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20895
+ * never the effective value. The camera's `motion` slice is the effective one,
20896
+ * so a view of the camera's own row reads this.
20897
+ * - `atMs`: when the bridge received the camera's last own edge.
20898
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20899
+ * AND it is younger than the window the bridge counts the camera's own motion
20900
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20901
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20902
+ * within the window; a status read is a snapshot, so a live view re-asks.
20903
+ * Absent = this orchestrator has not received the camera's own motion since it
20904
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20905
+ */
20906
+ var CameraRawLevelSchema = object({
20907
+ detected: boolean(),
20908
+ atMs: number()
20909
+ });
20936
20910
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
20937
- object({ state: literal("not-configured") }),
20911
+ object({
20912
+ state: literal("not-configured"),
20913
+ cameraLevel: CameraRawLevelSchema.optional()
20914
+ }),
20938
20915
  object({
20939
20916
  state: literal("unreadable"),
20940
- reason: string()
20917
+ reason: string(),
20918
+ cameraLevel: CameraRawLevelSchema.optional()
20941
20919
  }),
20942
20920
  object({
20943
20921
  state: literal("configured"),
20944
- mode: CameraSensorsModeSchema,
20922
+ cameraLevel: CameraRawLevelSchema.optional(),
20945
20923
  sensors: array(CameraSensorAttachmentSchema).readonly(),
20946
- notForwarded: CameraSensorsNotForwardedSchema.optional()
20924
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
20925
+ cameraMotion: CameraOwnMotionSchema.optional(),
20926
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
20927
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
20947
20928
  })
20948
20929
  ]);
20949
20930
  Object.freeze({
@@ -21628,14 +21609,14 @@ var TrackSchema = object({
21628
21609
  * `derive-returned-null tile=standin`,
21629
21610
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
21630
21611
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
21631
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
21612
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
21632
21613
  * tile is a face/plate stand-in, a raster crop, or an icon.
21633
21614
  *
21634
21615
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
21635
21616
  * the TILE ranked below native, so a track whose thumbnail landed natively
21636
21617
  * while its key frame missed carried no reason at all — three of the four
21637
21618
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
21638
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
21619
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
21639
21620
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
21640
21621
  * lastFrame copy source`), so its absence is now on this line whatever the
21641
21622
  * tile ended up being.
@@ -21722,7 +21703,7 @@ var MotionEventSchema = object({
21722
21703
  /**
21723
21704
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
21724
21705
  * first entry is always `0`) of every genuine off→on transition the
21725
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
21706
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
21726
21707
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
21727
21708
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
21728
21709
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -22246,6 +22227,7 @@ var KeyEventSchema = object({
22246
22227
  bestEventId: string(),
22247
22228
  /** Track lifetime in ms (lastSeen - firstSeen). */
22248
22229
  windowMs: number().optional(),
22230
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
22249
22231
  ...TrackFlagFields,
22250
22232
  ...TrackRetrainFields
22251
22233
  });
@@ -24174,8 +24156,10 @@ var RunnerCameraConfigSchema = object({
24174
24156
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24175
24157
  * analyzer providers) running on decoded frames in this runner.
24176
24158
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24177
- * analytics). The provider emits ProviderMotion
24178
- * events; the orchestrator forwards to `reportMotion`.
24159
+ * analytics). The provider emits its raw push as `ProviderMotion`
24160
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24161
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24162
+ * `reportMotion`.
24179
24163
  */
24180
24164
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24181
24165
  /**
@@ -24352,7 +24336,15 @@ var RunnerLocalLoadSchema = object({
24352
24336
  hasGpu: boolean(),
24353
24337
  inferenceBackend: string().optional(),
24354
24338
  cpuCores: number().optional()
24355
- })
24339
+ }),
24340
+ /**
24341
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24342
+ * runner never writes it. ABSENT = a runner older than D696, which still
24343
+ * writes the slice from its phase machine; the orchestrator does not write
24344
+ * while any runner node is absent-or-unanswered, so one slice never has two
24345
+ * writers.
24346
+ */
24347
+ motionSliceWriter: literal("orchestrator").optional()
24356
24348
  });
24357
24349
  /**
24358
24350
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -27017,7 +27009,7 @@ var ClipPlaybackSchema = object({
27017
27009
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
27018
27010
  * time the camera is awake for its own reasons — is deliberately not a member:
27019
27011
  * it was proposed, it is free on the battery, and the operator declined it on
27020
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
27012
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
27021
27013
  * D558 "Considered and not taken").
27022
27014
  */
27023
27015
  var ClipWakeSchema = _enum(["authorised"]);
@@ -27278,7 +27270,7 @@ DeviceType.Camera, method(object({
27278
27270
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
27279
27271
  * assumed the answer was a fan-out over everything a camera has. The
27280
27272
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
27281
- * solo"* — so the list is asked of one provider at a time and there is
27273
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
27282
27274
  * nothing to filter out of it.
27283
27275
  */
27284
27276
  provider: string().min(1)
@@ -29873,6 +29865,70 @@ onStatusChanged: { data: object({
29873
29865
  * whether persisting is worth a SQLite commit. */
29874
29866
  volatileStateFields: ["lastChangedAt"]
29875
29867
  };
29868
+ var DoorbellStatusSchema = object({
29869
+ /** Ms epoch of the last press. null = never observed since this provider started. */
29870
+ lastPressedAt: number().nullable(),
29871
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
29872
+ pressCountSinceStart: number()
29873
+ });
29874
+ var DoorbellPressEventSchema = object({
29875
+ deviceId: number(),
29876
+ timestamp: number()
29877
+ });
29878
+ /**
29879
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
29880
+ * they are the same cap:
29881
+ *
29882
+ * - **Native** providers, registered per device by a driver addon through
29883
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
29884
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
29885
+ * camera level). They emit `onPressed` on every firmware ring.
29886
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
29887
+ * the cap, its `lastPressedAt` rising from the sources the operator
29888
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
29889
+ * from that field's advance (`fromState`).
29890
+ *
29891
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
29892
+ */
29893
+ var doorbellCapability = {
29894
+ name: "doorbell",
29895
+ scope: "device",
29896
+ deviceNative: true,
29897
+ mode: "singleton",
29898
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
29899
+ methods: {},
29900
+ events: {
29901
+ /**
29902
+ * Fires once per physical press. Reolink delivers via Baichuan
29903
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
29904
+ * release/duration — it's a pulse.
29905
+ */
29906
+ onPressed: {
29907
+ data: DoorbellPressEventSchema,
29908
+ fromState: {
29909
+ field: "lastPressedAt",
29910
+ on: "advance"
29911
+ }
29912
+ } },
29913
+ status: {
29914
+ schema: DoorbellStatusSchema,
29915
+ kind: "push"
29916
+ },
29917
+ /**
29918
+ * Runtime-state slice — last press timestamp + lifetime press count.
29919
+ * Mirrored by the kernel and readable via
29920
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
29921
+ * without subscribing.
29922
+ */
29923
+ runtimeState: DoorbellStatusSchema,
29924
+ /**
29925
+ * 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.
29926
+ *
29927
+ * See `RuntimeStateDurability`. Enforced by
29928
+ * `scripts/check-runtime-state-durability.ts`.
29929
+ */
29930
+ durability: "restored"
29931
+ };
29876
29932
  /**
29877
29933
  * Enum-state sensor — a string value picked from a finite option set.
29878
29934
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -32017,9 +32073,9 @@ var MotionStatusSchema = object({
32017
32073
  /** Ms epoch of the last detected-true observation. Null if never detected. */
32018
32074
  lastDetectedAt: number().nullable(),
32019
32075
  /**
32020
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
32021
- * `null` while false and on every `Sensor` device (D475) — see that
32022
- * constant's doc for the one-authority rule.
32076
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
32077
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
32078
+ * device (D475) — see that constant's doc for the one-authority rule.
32023
32079
  *
32024
32080
  * ## Reading this field still arms nothing
32025
32081
  *
@@ -32037,34 +32093,31 @@ var MotionStatusSchema = object({
32037
32093
  * `addon-export-alexa/src/motion-clear-hold.ts` and
32038
32094
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
32039
32095
  *
32040
- * ## Who writes it
32041
- *
32042
- * - **Cameras** — the runner's phase machine, `active → watching` on
32043
- * `cooldown_expired`, which then writes this slice with
32044
- * `detected: false` (`handlePhaseChanged` in
32045
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
32046
- * matters most for the sources that only ever push a rising one:
32047
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
32048
- * a false.
32049
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
32050
- * provider pushes the false itself, from the upstream system's own
32051
- * state change. No phase machine is involved.
32052
- *
32053
- * ### The phase machine is CANONICAL, not sole — and that is a defect
32054
- *
32055
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
32056
- * phase machine is the sole writer for a camera. It is not.
32057
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
32058
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
32059
- * Hikvision's comment says why: it read THIS docblock, agreed the
32060
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
32061
- * two authorities can disagree about one slice, which this repo
32062
- * forbids, and the doc said otherwise — which is worse than saying
32063
- * nothing, because it reads as verification.
32064
- *
32065
- * This predates D475 and is not fixed there: the fix touches every
32066
- * camera provider. Recorded in D475's Consequences. Do not restore the
32067
- * "sole writer" wording without also removing the other writers.
32096
+ * ## Who writes it (D696)
32097
+ *
32098
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
32099
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
32100
+ * `camera-sensors/motion-slice.ts`), alongside the effective
32101
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
32102
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
32103
+ * device activity, as the camera's `motionSources` counts them. A source
32104
+ * that never sends a clear falls one window after its last `true`.
32105
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
32106
+ * writes this slice (not even a boot seed), and neither does the runner's
32107
+ * phase machine: its phase is "a session is attached" for every on-motion
32108
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
32109
+ * A provider's `isDetected` answers from the hub's slice.
32110
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32111
+ * imports) — the provider pushes both edges itself, from the upstream
32112
+ * system's own state change. That is the sensor's own fact.
32113
+ *
32114
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
32115
+ * `motion` slice; each sensor writer is a named exemption.
32116
+ *
32117
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
32118
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
32119
+ * it, every provider seeded it at boot, and every session left it
32120
+ * `detected: true` after its detach.
32068
32121
  */
32069
32122
  autoClearAfterMs: number().nullable()
32070
32123
  });
@@ -32136,11 +32189,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
32136
32189
  */
32137
32190
  runtimeState: MotionStatusSchema,
32138
32191
  /**
32139
- * Runtime-state durability: **session** — every writer of this slice
32192
+ * Runtime-state durability: **session** — the writer of this slice
32140
32193
  * writes only on an EDGE, so a restored `detected: true` would stay
32141
32194
  * frozen until the next one instead of being corrected. The next edge
32142
- * re-publishes the real state. (On who the writers are, and why there
32143
- * is more than one, see `autoClearAfterMs` above.)
32195
+ * re-publishes the real state, and the orchestrator re-publishes every
32196
+ * camera when it starts writing (D696; on who writes it, see
32197
+ * `autoClearAfterMs` above).
32144
32198
  *
32145
32199
  * See `RuntimeStateDurability`. Enforced by
32146
32200
  * `scripts/check-runtime-state-durability.ts`.
@@ -34523,8 +34577,7 @@ var ptzAutotrackCapability = {
34523
34577
  deviceNative: true,
34524
34578
  mode: "singleton",
34525
34579
  /**
34526
- * Two kinds of provider behind one name, the same shape `snapshot` and
34527
- * `doorbell` use:
34580
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
34528
34581
  *
34529
34582
  * - **Native**: the camera's own firmware autotrack, registered per device by
34530
34583
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -34532,7 +34585,7 @@ var ptzAutotrackCapability = {
34532
34585
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
34533
34586
  * which follows a subject with `ptz.move` pulses driven by the detection
34534
34587
  * pipeline. `defaultActive: false` — the operator binds it per camera in
34535
- * the bindings UI, exactly as `virtual-doorbell` is bound.
34588
+ * the bindings UI.
34536
34589
  *
34537
34590
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
34538
34591
  * one switch for the function either way. A camera never has both driving its
@@ -35207,7 +35260,7 @@ var ReadGopBytesResultSchema = object({
35207
35260
  /**
35208
35261
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
35209
35262
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
35210
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
35263
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
35211
35264
  * a replay needs several seconds of native pixels, not one frame.
35212
35265
  *
35213
35266
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -38571,6 +38624,7 @@ var zoneRulesCapability = {
38571
38624
  */
38572
38625
  durability: "restored"
38573
38626
  };
38627
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
38574
38628
  /**
38575
38629
  * Accessory device helpers — shared across drivers.
38576
38630
  *
@@ -39630,13 +39684,14 @@ var BaseDeviceProvider = class extends BaseAddon {
39630
39684
  async getStatus() {
39631
39685
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
39632
39686
  const summary = this.restoreFailureSummary();
39633
- if (summary === null) return {
39687
+ const base = {
39634
39688
  connected: true,
39635
- deviceCount: all.length
39689
+ deviceCount: all.length,
39690
+ motionSliceWriter: "orchestrator"
39636
39691
  };
39692
+ if (summary === null) return base;
39637
39693
  return {
39638
- connected: true,
39639
- deviceCount: all.length,
39694
+ ...base,
39640
39695
  error: summary
39641
39696
  };
39642
39697
  }
@@ -45072,6 +45127,12 @@ Object.freeze({
45072
45127
  addonId: null,
45073
45128
  access: "view"
45074
45129
  },
45130
+ "notificationRules.getAlarmSensors": {
45131
+ capName: "notification-rules",
45132
+ capScope: "system",
45133
+ addonId: null,
45134
+ access: "view"
45135
+ },
45075
45136
  "notificationRules.getClipRetentionAsks": {
45076
45137
  capName: "notification-rules",
45077
45138
  capScope: "system",
@@ -48650,6 +48711,11 @@ Object.freeze({
48650
48711
  }
48651
48712
  });
48652
48713
  Object.freeze({
48714
+ "accessories.getStatus": [{
48715
+ name: "deviceId",
48716
+ form: "single",
48717
+ optional: false
48718
+ }],
48653
48719
  "accessories.setChildHidden": [{
48654
48720
  name: "childDeviceId",
48655
48721
  form: "single",
@@ -48669,6 +48735,11 @@ Object.freeze({
48669
48735
  form: "single",
48670
48736
  optional: false
48671
48737
  }],
48738
+ "airQualitySensor.getStatus": [{
48739
+ name: "deviceId",
48740
+ form: "single",
48741
+ optional: false
48742
+ }],
48672
48743
  "alarmPanel.arm": [{
48673
48744
  name: "deviceId",
48674
48745
  form: "single",
@@ -48679,11 +48750,36 @@ Object.freeze({
48679
48750
  form: "single",
48680
48751
  optional: false
48681
48752
  }],
48753
+ "alarmPanel.getStatus": [{
48754
+ name: "deviceId",
48755
+ form: "single",
48756
+ optional: false
48757
+ }],
48682
48758
  "alarmPanel.trigger": [{
48683
48759
  name: "deviceId",
48684
48760
  form: "single",
48685
48761
  optional: false
48686
48762
  }],
48763
+ "ambientLightSensor.getStatus": [{
48764
+ name: "deviceId",
48765
+ form: "single",
48766
+ optional: false
48767
+ }],
48768
+ "audioAnalysis.applyDeviceSettingsPatch": [{
48769
+ name: "deviceId",
48770
+ form: "single",
48771
+ optional: false
48772
+ }],
48773
+ "audioAnalysis.getDeviceLiveContribution": [{
48774
+ name: "deviceId",
48775
+ form: "single",
48776
+ optional: false
48777
+ }],
48778
+ "audioAnalysis.getDeviceSettingsContribution": [{
48779
+ name: "deviceId",
48780
+ form: "single",
48781
+ optional: false
48782
+ }],
48687
48783
  "audioAnalysis.resolveDeviceSettings": [{
48688
48784
  name: "deviceId",
48689
48785
  form: "single",
@@ -48724,16 +48820,36 @@ Object.freeze({
48724
48820
  form: "single",
48725
48821
  optional: false
48726
48822
  }],
48823
+ "automationControl.getStatus": [{
48824
+ name: "deviceId",
48825
+ form: "single",
48826
+ optional: false
48827
+ }],
48727
48828
  "automationControl.trigger": [{
48728
48829
  name: "deviceId",
48729
48830
  form: "single",
48730
48831
  optional: false
48731
48832
  }],
48833
+ "battery.getStatus": [{
48834
+ name: "deviceId",
48835
+ form: "single",
48836
+ optional: false
48837
+ }],
48732
48838
  "battery.wakeForStream": [{
48733
48839
  name: "deviceId",
48734
48840
  form: "single",
48735
48841
  optional: false
48736
48842
  }],
48843
+ "binary.getStatus": [{
48844
+ name: "deviceId",
48845
+ form: "single",
48846
+ optional: false
48847
+ }],
48848
+ "brightness.getStatus": [{
48849
+ name: "deviceId",
48850
+ form: "single",
48851
+ optional: false
48852
+ }],
48737
48853
  "brightness.setBrightness": [{
48738
48854
  name: "deviceId",
48739
48855
  form: "single",
@@ -48749,6 +48865,26 @@ Object.freeze({
48749
48865
  form: "single",
48750
48866
  optional: false
48751
48867
  }],
48868
+ "cameraCredentials.getStatus": [{
48869
+ name: "deviceId",
48870
+ form: "single",
48871
+ optional: false
48872
+ }],
48873
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
48874
+ name: "deviceId",
48875
+ form: "single",
48876
+ optional: false
48877
+ }],
48878
+ "cameraGridLayout.getDeviceLiveContribution": [{
48879
+ name: "deviceId",
48880
+ form: "single",
48881
+ optional: false
48882
+ }],
48883
+ "cameraGridLayout.getDeviceSettingsContribution": [{
48884
+ name: "deviceId",
48885
+ form: "single",
48886
+ optional: false
48887
+ }],
48752
48888
  "cameraGridLayout.getLayout": [{
48753
48889
  name: "deviceId",
48754
48890
  form: "single",
@@ -48764,6 +48900,21 @@ Object.freeze({
48764
48900
  form: "single",
48765
48901
  optional: false
48766
48902
  }],
48903
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
48904
+ name: "deviceId",
48905
+ form: "single",
48906
+ optional: false
48907
+ }],
48908
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
48909
+ name: "deviceId",
48910
+ form: "single",
48911
+ optional: false
48912
+ }],
48913
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
48914
+ name: "deviceId",
48915
+ form: "single",
48916
+ optional: false
48917
+ }],
48767
48918
  "cameraStreams.getBrokerStreams": [{
48768
48919
  name: "deviceId",
48769
48920
  form: "single",
@@ -48789,6 +48940,16 @@ Object.freeze({
48789
48940
  form: "single",
48790
48941
  optional: false
48791
48942
  }],
48943
+ "carbonMonoxide.getStatus": [{
48944
+ name: "deviceId",
48945
+ form: "single",
48946
+ optional: false
48947
+ }],
48948
+ "climateControl.getStatus": [{
48949
+ name: "deviceId",
48950
+ form: "single",
48951
+ optional: false
48952
+ }],
48792
48953
  "climateControl.setFanMode": [{
48793
48954
  name: "deviceId",
48794
48955
  form: "single",
@@ -48829,16 +48990,41 @@ Object.freeze({
48829
48990
  form: "single",
48830
48991
  optional: false
48831
48992
  }],
48993
+ "color.getStatus": [{
48994
+ name: "deviceId",
48995
+ form: "single",
48996
+ optional: false
48997
+ }],
48832
48998
  "color.setColor": [{
48833
48999
  name: "deviceId",
48834
49000
  form: "single",
48835
49001
  optional: false
48836
49002
  }],
49003
+ "connectivity.getStatus": [{
49004
+ name: "deviceId",
49005
+ form: "single",
49006
+ optional: false
49007
+ }],
49008
+ "consumables.getStatus": [{
49009
+ name: "deviceId",
49010
+ form: "single",
49011
+ optional: false
49012
+ }],
48837
49013
  "consumables.reset": [{
48838
49014
  name: "deviceId",
48839
49015
  form: "single",
48840
49016
  optional: false
48841
49017
  }],
49018
+ "contact.getStatus": [{
49019
+ name: "deviceId",
49020
+ form: "single",
49021
+ optional: false
49022
+ }],
49023
+ "control.getStatus": [{
49024
+ name: "deviceId",
49025
+ form: "single",
49026
+ optional: false
49027
+ }],
48842
49028
  "control.setValue": [{
48843
49029
  name: "deviceId",
48844
49030
  form: "single",
@@ -48849,6 +49035,11 @@ Object.freeze({
48849
49035
  form: "single",
48850
49036
  optional: false
48851
49037
  }],
49038
+ "cover.getStatus": [{
49039
+ name: "deviceId",
49040
+ form: "single",
49041
+ optional: false
49042
+ }],
48852
49043
  "cover.open": [{
48853
49044
  name: "deviceId",
48854
49045
  form: "single",
@@ -48874,6 +49065,11 @@ Object.freeze({
48874
49065
  form: "single",
48875
49066
  optional: false
48876
49067
  }],
49068
+ "dayNight.getStatus": [{
49069
+ name: "deviceId",
49070
+ form: "single",
49071
+ optional: false
49072
+ }],
48877
49073
  "dayNight.setSettings": [{
48878
49074
  name: "deviceId",
48879
49075
  form: "single",
@@ -48884,11 +49080,31 @@ Object.freeze({
48884
49080
  form: "single",
48885
49081
  optional: true
48886
49082
  }],
49083
+ "detectionPipeline.applyDeviceSettingsPatch": [{
49084
+ name: "deviceId",
49085
+ form: "single",
49086
+ optional: false
49087
+ }],
49088
+ "detectionPipeline.getDeviceLiveContribution": [{
49089
+ name: "deviceId",
49090
+ form: "single",
49091
+ optional: false
49092
+ }],
49093
+ "detectionPipeline.getDeviceSettingsContribution": [{
49094
+ name: "deviceId",
49095
+ form: "single",
49096
+ optional: false
49097
+ }],
48887
49098
  "deviceAdminLink.getAdminLink": [{
48888
49099
  name: "deviceId",
48889
49100
  form: "single",
48890
49101
  optional: false
48891
49102
  }],
49103
+ "deviceAdoption.getStatus": [{
49104
+ name: "deviceId",
49105
+ form: "single",
49106
+ optional: false
49107
+ }],
48892
49108
  "deviceAdoption.release": [{
48893
49109
  name: "camDeviceId",
48894
49110
  form: "single",
@@ -48904,6 +49120,11 @@ Object.freeze({
48904
49120
  form: "single",
48905
49121
  optional: false
48906
49122
  }],
49123
+ "deviceDiscovery.getStatus": [{
49124
+ name: "deviceId",
49125
+ form: "single",
49126
+ optional: false
49127
+ }],
48907
49128
  "deviceDiscovery.listDiscovered": [{
48908
49129
  name: "deviceId",
48909
49130
  form: "single",
@@ -48923,6 +49144,21 @@ Object.freeze({
48923
49144
  form: "single",
48924
49145
  optional: false
48925
49146
  }],
49147
+ "deviceExport.applyDeviceSettingsPatch": [{
49148
+ name: "deviceId",
49149
+ form: "single",
49150
+ optional: false
49151
+ }],
49152
+ "deviceExport.getDeviceLiveContribution": [{
49153
+ name: "deviceId",
49154
+ form: "single",
49155
+ optional: false
49156
+ }],
49157
+ "deviceExport.getDeviceSettingsContribution": [{
49158
+ name: "deviceId",
49159
+ form: "single",
49160
+ optional: false
49161
+ }],
48926
49162
  "deviceExtension.listCandidates": [{
48927
49163
  name: "deviceId",
48928
49164
  form: "single",
@@ -49271,6 +49507,26 @@ Object.freeze({
49271
49507
  form: "single",
49272
49508
  optional: false
49273
49509
  }],
49510
+ "deviceStatus.getStatus": [{
49511
+ name: "deviceId",
49512
+ form: "single",
49513
+ optional: false
49514
+ }],
49515
+ "doorbell.getStatus": [{
49516
+ name: "deviceId",
49517
+ form: "single",
49518
+ optional: false
49519
+ }],
49520
+ "enumSensor.getStatus": [{
49521
+ name: "deviceId",
49522
+ form: "single",
49523
+ optional: false
49524
+ }],
49525
+ "eventEmitter.getStatus": [{
49526
+ name: "deviceId",
49527
+ form: "single",
49528
+ optional: false
49529
+ }],
49274
49530
  "faceGallery.getFaceByTrack": [{
49275
49531
  name: "deviceId",
49276
49532
  form: "single",
@@ -49285,6 +49541,11 @@ Object.freeze({
49285
49541
  form: "array",
49286
49542
  optional: true
49287
49543
  }],
49544
+ "fanControl.getStatus": [{
49545
+ name: "deviceId",
49546
+ form: "single",
49547
+ optional: false
49548
+ }],
49288
49549
  "fanControl.setDirection": [{
49289
49550
  name: "deviceId",
49290
49551
  form: "single",
@@ -49305,6 +49566,26 @@ Object.freeze({
49305
49566
  form: "single",
49306
49567
  optional: false
49307
49568
  }],
49569
+ "featureProbe.getStatus": [{
49570
+ name: "deviceId",
49571
+ form: "single",
49572
+ optional: false
49573
+ }],
49574
+ "flood.getStatus": [{
49575
+ name: "deviceId",
49576
+ form: "single",
49577
+ optional: false
49578
+ }],
49579
+ "gas.getStatus": [{
49580
+ name: "deviceId",
49581
+ form: "single",
49582
+ optional: false
49583
+ }],
49584
+ "humidifier.getStatus": [{
49585
+ name: "deviceId",
49586
+ form: "single",
49587
+ optional: false
49588
+ }],
49308
49589
  "humidifier.setMode": [{
49309
49590
  name: "deviceId",
49310
49591
  form: "single",
@@ -49320,11 +49601,26 @@ Object.freeze({
49320
49601
  form: "single",
49321
49602
  optional: false
49322
49603
  }],
49604
+ "humiditySensor.getStatus": [{
49605
+ name: "deviceId",
49606
+ form: "single",
49607
+ optional: false
49608
+ }],
49609
+ "image.getStatus": [{
49610
+ name: "deviceId",
49611
+ form: "single",
49612
+ optional: false
49613
+ }],
49323
49614
  "imageSettings.getOptions": [{
49324
49615
  name: "deviceId",
49325
49616
  form: "single",
49326
49617
  optional: false
49327
49618
  }],
49619
+ "imageSettings.getStatus": [{
49620
+ name: "deviceId",
49621
+ form: "single",
49622
+ optional: false
49623
+ }],
49328
49624
  "imageSettings.setSettings": [{
49329
49625
  name: "deviceId",
49330
49626
  form: "single",
@@ -49335,6 +49631,11 @@ Object.freeze({
49335
49631
  form: "single",
49336
49632
  optional: false
49337
49633
  }],
49634
+ "intercom.getStatus": [{
49635
+ name: "deviceId",
49636
+ form: "single",
49637
+ optional: false
49638
+ }],
49338
49639
  "intercom.handleAnswer": [{
49339
49640
  name: "deviceId",
49340
49641
  form: "single",
@@ -49365,6 +49666,11 @@ Object.freeze({
49365
49666
  form: "single",
49366
49667
  optional: false
49367
49668
  }],
49669
+ "lawnMowerControl.getStatus": [{
49670
+ name: "deviceId",
49671
+ form: "single",
49672
+ optional: false
49673
+ }],
49368
49674
  "lawnMowerControl.pause": [{
49369
49675
  name: "deviceId",
49370
49676
  form: "single",
@@ -49375,6 +49681,11 @@ Object.freeze({
49375
49681
  form: "single",
49376
49682
  optional: false
49377
49683
  }],
49684
+ "lockControl.getStatus": [{
49685
+ name: "deviceId",
49686
+ form: "single",
49687
+ optional: false
49688
+ }],
49378
49689
  "lockControl.lock": [{
49379
49690
  name: "deviceId",
49380
49691
  form: "single",
@@ -49390,6 +49701,11 @@ Object.freeze({
49390
49701
  form: "single",
49391
49702
  optional: false
49392
49703
  }],
49704
+ "mediaPlayer.getStatus": [{
49705
+ name: "deviceId",
49706
+ form: "single",
49707
+ optional: false
49708
+ }],
49393
49709
  "mediaPlayer.next": [{
49394
49710
  name: "deviceId",
49395
49711
  form: "single",
@@ -49450,6 +49766,11 @@ Object.freeze({
49450
49766
  form: "single",
49451
49767
  optional: false
49452
49768
  }],
49769
+ "motion.getStatus": [{
49770
+ name: "deviceId",
49771
+ form: "single",
49772
+ optional: false
49773
+ }],
49453
49774
  "motion.isDetected": [{
49454
49775
  name: "deviceId",
49455
49776
  form: "single",
@@ -49460,11 +49781,31 @@ Object.freeze({
49460
49781
  form: "single",
49461
49782
  optional: false
49462
49783
  }],
49784
+ "motionDetection.applyDeviceSettingsPatch": [{
49785
+ name: "deviceId",
49786
+ form: "single",
49787
+ optional: false
49788
+ }],
49789
+ "motionDetection.getDeviceLiveContribution": [{
49790
+ name: "deviceId",
49791
+ form: "single",
49792
+ optional: false
49793
+ }],
49794
+ "motionDetection.getDeviceSettingsContribution": [{
49795
+ name: "deviceId",
49796
+ form: "single",
49797
+ optional: false
49798
+ }],
49463
49799
  "motionDetection.removeCamera": [{
49464
49800
  name: "deviceId",
49465
49801
  form: "single",
49466
49802
  optional: false
49467
49803
  }],
49804
+ "motionTrigger.getStatus": [{
49805
+ name: "deviceId",
49806
+ form: "single",
49807
+ optional: false
49808
+ }],
49468
49809
  "motionTrigger.setMotionTrigger": [{
49469
49810
  name: "deviceId",
49470
49811
  form: "single",
@@ -49475,6 +49816,11 @@ Object.freeze({
49475
49816
  form: "single",
49476
49817
  optional: false
49477
49818
  }],
49819
+ "motionZones.getStatus": [{
49820
+ name: "deviceId",
49821
+ form: "single",
49822
+ optional: false
49823
+ }],
49478
49824
  "motionZones.setZone": [{
49479
49825
  name: "deviceId",
49480
49826
  form: "single",
@@ -49485,6 +49831,11 @@ Object.freeze({
49485
49831
  form: "single",
49486
49832
  optional: false
49487
49833
  }],
49834
+ "nativeObjectDetection.getStatus": [{
49835
+ name: "deviceId",
49836
+ form: "single",
49837
+ optional: false
49838
+ }],
49488
49839
  "nativeObjectDetection.setEnabled": [{
49489
49840
  name: "deviceId",
49490
49841
  form: "single",
@@ -49500,6 +49851,11 @@ Object.freeze({
49500
49851
  form: "single",
49501
49852
  optional: false
49502
49853
  }],
49854
+ "navigation.getStatus": [{
49855
+ name: "deviceId",
49856
+ form: "single",
49857
+ optional: false
49858
+ }],
49503
49859
  "navigation.goToPoint": [{
49504
49860
  name: "deviceId",
49505
49861
  form: "single",
@@ -49545,6 +49901,11 @@ Object.freeze({
49545
49901
  form: "single",
49546
49902
  optional: false
49547
49903
  }],
49904
+ "networkLink.getStatus": [{
49905
+ name: "deviceId",
49906
+ form: "single",
49907
+ optional: false
49908
+ }],
49548
49909
  "networkQuality.getDeviceStats": [{
49549
49910
  name: "deviceId",
49550
49911
  form: "single",
@@ -49555,6 +49916,11 @@ Object.freeze({
49555
49916
  form: "single",
49556
49917
  optional: false
49557
49918
  }],
49919
+ "notificationRules.getAlarmSensors": [{
49920
+ name: "deviceIds",
49921
+ form: "array",
49922
+ optional: false
49923
+ }],
49558
49924
  "notificationRules.setDeviceMuted": [{
49559
49925
  name: "deviceId",
49560
49926
  form: "single",
@@ -49565,11 +49931,26 @@ Object.freeze({
49565
49931
  form: "single",
49566
49932
  optional: false
49567
49933
  }],
49934
+ "notifier.getStatus": [{
49935
+ name: "deviceId",
49936
+ form: "single",
49937
+ optional: false
49938
+ }],
49568
49939
  "notifier.send": [{
49569
49940
  name: "deviceId",
49570
49941
  form: "single",
49571
49942
  optional: false
49572
49943
  }],
49944
+ "numericSensor.getStatus": [{
49945
+ name: "deviceId",
49946
+ form: "single",
49947
+ optional: false
49948
+ }],
49949
+ "osd.getStatus": [{
49950
+ name: "deviceId",
49951
+ form: "single",
49952
+ optional: false
49953
+ }],
49573
49954
  "osd.setOverlay": [{
49574
49955
  name: "deviceId",
49575
49956
  form: "single",
@@ -49629,6 +50010,11 @@ Object.freeze({
49629
50010
  form: "single",
49630
50011
  optional: false
49631
50012
  }],
50013
+ "petFeeder.getStatus": [{
50014
+ name: "deviceId",
50015
+ form: "single",
50016
+ optional: false
50017
+ }],
49632
50018
  "petFeeder.markFoodReplenished": [{
49633
50019
  name: "deviceId",
49634
50020
  form: "single",
@@ -49664,6 +50050,11 @@ Object.freeze({
49664
50050
  form: "single",
49665
50051
  optional: false
49666
50052
  }],
50053
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
50054
+ name: "deviceId",
50055
+ form: "single",
50056
+ optional: false
50057
+ }],
49667
50058
  "pipelineAnalytics.clearTrackRelation": [{
49668
50059
  name: "deviceId",
49669
50060
  form: "single",
@@ -49704,6 +50095,16 @@ Object.freeze({
49704
50095
  form: "single",
49705
50096
  optional: false
49706
50097
  }],
50098
+ "pipelineAnalytics.getDeviceLiveContribution": [{
50099
+ name: "deviceId",
50100
+ form: "single",
50101
+ optional: false
50102
+ }],
50103
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
50104
+ name: "deviceId",
50105
+ form: "single",
50106
+ optional: false
50107
+ }],
49707
50108
  "pipelineAnalytics.getEventDensity": [{
49708
50109
  name: "deviceId",
49709
50110
  form: "single",
@@ -49919,6 +50320,11 @@ Object.freeze({
49919
50320
  form: "single",
49920
50321
  optional: true
49921
50322
  }],
50323
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
50324
+ name: "deviceId",
50325
+ form: "single",
50326
+ optional: false
50327
+ }],
49922
50328
  "pipelineOrchestrator.assignAudio": [{
49923
50329
  name: "deviceId",
49924
50330
  form: "single",
@@ -49964,6 +50370,16 @@ Object.freeze({
49964
50370
  form: "single",
49965
50371
  optional: false
49966
50372
  }],
50373
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
50374
+ name: "deviceId",
50375
+ form: "single",
50376
+ optional: false
50377
+ }],
50378
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
50379
+ name: "deviceId",
50380
+ form: "single",
50381
+ optional: false
50382
+ }],
49967
50383
  "pipelineOrchestrator.getPipelineAssignment": [{
49968
50384
  name: "deviceId",
49969
50385
  form: "single",
@@ -50084,11 +50500,31 @@ Object.freeze({
50084
50500
  form: "single",
50085
50501
  optional: true
50086
50502
  }],
50503
+ "powerMeter.getStatus": [{
50504
+ name: "deviceId",
50505
+ form: "single",
50506
+ optional: false
50507
+ }],
50508
+ "presence.getStatus": [{
50509
+ name: "deviceId",
50510
+ form: "single",
50511
+ optional: false
50512
+ }],
50513
+ "pressureSensor.getStatus": [{
50514
+ name: "deviceId",
50515
+ form: "single",
50516
+ optional: false
50517
+ }],
50087
50518
  "privacyMask.getOptions": [{
50088
50519
  name: "deviceId",
50089
50520
  form: "single",
50090
50521
  optional: false
50091
50522
  }],
50523
+ "privacyMask.getStatus": [{
50524
+ name: "deviceId",
50525
+ form: "single",
50526
+ optional: false
50527
+ }],
50092
50528
  "privacyMask.setAudioEnabled": [{
50093
50529
  name: "deviceId",
50094
50530
  form: "single",
@@ -50139,6 +50575,11 @@ Object.freeze({
50139
50575
  form: "single",
50140
50576
  optional: false
50141
50577
  }],
50578
+ "ptz.getStatus": [{
50579
+ name: "deviceId",
50580
+ form: "single",
50581
+ optional: false
50582
+ }],
50142
50583
  "ptz.goHome": [{
50143
50584
  name: "deviceId",
50144
50585
  form: "single",
@@ -50229,6 +50670,11 @@ Object.freeze({
50229
50670
  form: "single",
50230
50671
  optional: false
50231
50672
  }],
50673
+ "recordingArchive.applyDeviceSettingsPatch": [{
50674
+ name: "deviceId",
50675
+ form: "single",
50676
+ optional: false
50677
+ }],
50232
50678
  "recordingArchive.deleteFootprint": [{
50233
50679
  name: "deviceId",
50234
50680
  form: "single",
@@ -50249,6 +50695,21 @@ Object.freeze({
50249
50695
  form: "single",
50250
50696
  optional: false
50251
50697
  }],
50698
+ "recordingArchive.getDeviceLiveContribution": [{
50699
+ name: "deviceId",
50700
+ form: "single",
50701
+ optional: false
50702
+ }],
50703
+ "recordingArchive.getDeviceSettingsContribution": [{
50704
+ name: "deviceId",
50705
+ form: "single",
50706
+ optional: false
50707
+ }],
50708
+ "recordingArchive.getStatus": [{
50709
+ name: "deviceId",
50710
+ form: "single",
50711
+ optional: false
50712
+ }],
50252
50713
  "recordingArchive.listOpsLog": [{
50253
50714
  name: "deviceId",
50254
50715
  form: "single",
@@ -50334,6 +50795,11 @@ Object.freeze({
50334
50795
  form: "single",
50335
50796
  optional: false
50336
50797
  }],
50798
+ "recordingOnboard.getStatus": [{
50799
+ name: "deviceId",
50800
+ form: "single",
50801
+ optional: false
50802
+ }],
50337
50803
  "recordingOnboard.setSettings": [{
50338
50804
  name: "deviceId",
50339
50805
  form: "single",
@@ -50364,6 +50830,11 @@ Object.freeze({
50364
50830
  form: "single",
50365
50831
  optional: false
50366
50832
  }],
50833
+ "sceneMonitor.getStatus": [{
50834
+ name: "deviceId",
50835
+ form: "single",
50836
+ optional: false
50837
+ }],
50367
50838
  "sceneMonitor.listScenes": [{
50368
50839
  name: "deviceId",
50369
50840
  form: "single",
@@ -50389,6 +50860,11 @@ Object.freeze({
50389
50860
  form: "single",
50390
50861
  optional: false
50391
50862
  }],
50863
+ "scriptRunner.getStatus": [{
50864
+ name: "deviceId",
50865
+ form: "single",
50866
+ optional: false
50867
+ }],
50392
50868
  "scriptRunner.run": [{
50393
50869
  name: "deviceId",
50394
50870
  form: "single",
@@ -50399,11 +50875,31 @@ Object.freeze({
50399
50875
  form: "single",
50400
50876
  optional: false
50401
50877
  }],
50878
+ "smoke.getStatus": [{
50879
+ name: "deviceId",
50880
+ form: "single",
50881
+ optional: false
50882
+ }],
50883
+ "snapshot.applyDeviceSettingsPatch": [{
50884
+ name: "deviceId",
50885
+ form: "single",
50886
+ optional: false
50887
+ }],
50402
50888
  "snapshot.getDebugState": [{
50403
50889
  name: "deviceId",
50404
50890
  form: "single",
50405
50891
  optional: false
50406
50892
  }],
50893
+ "snapshot.getDeviceLiveContribution": [{
50894
+ name: "deviceId",
50895
+ form: "single",
50896
+ optional: false
50897
+ }],
50898
+ "snapshot.getDeviceSettingsContribution": [{
50899
+ name: "deviceId",
50900
+ form: "single",
50901
+ optional: false
50902
+ }],
50407
50903
  "snapshot.getSnapshot": [{
50408
50904
  name: "deviceId",
50409
50905
  form: "single",
@@ -50420,6 +50916,11 @@ Object.freeze({
50420
50916
  form: "array",
50421
50917
  optional: false
50422
50918
  }],
50919
+ "snapshot.getStatus": [{
50920
+ name: "deviceId",
50921
+ form: "single",
50922
+ optional: false
50923
+ }],
50423
50924
  "snapshot.invalidateCache": [{
50424
50925
  name: "deviceId",
50425
50926
  form: "single",
@@ -50430,6 +50931,11 @@ Object.freeze({
50430
50931
  form: "single",
50431
50932
  optional: false
50432
50933
  }],
50934
+ "streamBroker.applyDeviceSettingsPatch": [{
50935
+ name: "deviceId",
50936
+ form: "single",
50937
+ optional: false
50938
+ }],
50433
50939
  "streamBroker.assignProfile": [{
50434
50940
  name: "deviceId",
50435
50941
  form: "single",
@@ -50445,6 +50951,16 @@ Object.freeze({
50445
50951
  form: "single",
50446
50952
  optional: false
50447
50953
  }],
50954
+ "streamBroker.getDeviceLiveContribution": [{
50955
+ name: "deviceId",
50956
+ form: "single",
50957
+ optional: false
50958
+ }],
50959
+ "streamBroker.getDeviceSettingsContribution": [{
50960
+ name: "deviceId",
50961
+ form: "single",
50962
+ optional: false
50963
+ }],
50448
50964
  "streamBroker.getStreamWithCodec": [{
50449
50965
  name: "deviceId",
50450
50966
  form: "single",
@@ -50505,16 +51021,46 @@ Object.freeze({
50505
51021
  form: "single",
50506
51022
  optional: false
50507
51023
  }],
51024
+ "streamParams.getStatus": [{
51025
+ name: "deviceId",
51026
+ form: "single",
51027
+ optional: false
51028
+ }],
50508
51029
  "streamParams.setProfile": [{
50509
51030
  name: "deviceId",
50510
51031
  form: "single",
50511
51032
  optional: false
50512
51033
  }],
51034
+ "switch.getStatus": [{
51035
+ name: "deviceId",
51036
+ form: "single",
51037
+ optional: false
51038
+ }],
50513
51039
  "switch.setState": [{
50514
51040
  name: "deviceId",
50515
51041
  form: "single",
50516
51042
  optional: false
50517
51043
  }],
51044
+ "tamper.getStatus": [{
51045
+ name: "deviceId",
51046
+ form: "single",
51047
+ optional: false
51048
+ }],
51049
+ "temperatureSensor.getStatus": [{
51050
+ name: "deviceId",
51051
+ form: "single",
51052
+ optional: false
51053
+ }],
51054
+ "update.getStatus": [{
51055
+ name: "deviceId",
51056
+ form: "single",
51057
+ optional: false
51058
+ }],
51059
+ "vacuumControl.getStatus": [{
51060
+ name: "deviceId",
51061
+ form: "single",
51062
+ optional: false
51063
+ }],
50518
51064
  "vacuumControl.locate": [{
50519
51065
  name: "deviceId",
50520
51066
  form: "single",
@@ -50550,6 +51096,11 @@ Object.freeze({
50550
51096
  form: "single",
50551
51097
  optional: false
50552
51098
  }],
51099
+ "valve.getStatus": [{
51100
+ name: "deviceId",
51101
+ form: "single",
51102
+ optional: false
51103
+ }],
50553
51104
  "valve.open": [{
50554
51105
  name: "deviceId",
50555
51106
  form: "single",
@@ -50565,6 +51116,11 @@ Object.freeze({
50565
51116
  form: "single",
50566
51117
  optional: false
50567
51118
  }],
51119
+ "vibration.getStatus": [{
51120
+ name: "deviceId",
51121
+ form: "single",
51122
+ optional: false
51123
+ }],
50568
51124
  "videoclips.dialClipStream": [{
50569
51125
  name: "deviceId",
50570
51126
  form: "single",
@@ -50600,6 +51156,11 @@ Object.freeze({
50600
51156
  form: "single",
50601
51157
  optional: false
50602
51158
  }],
51159
+ "waterHeater.getStatus": [{
51160
+ name: "deviceId",
51161
+ form: "single",
51162
+ optional: false
51163
+ }],
50603
51164
  "waterHeater.setAway": [{
50604
51165
  name: "deviceId",
50605
51166
  form: "single",
@@ -50615,6 +51176,11 @@ Object.freeze({
50615
51176
  form: "single",
50616
51177
  optional: false
50617
51178
  }],
51179
+ "weather.getStatus": [{
51180
+ name: "deviceId",
51181
+ form: "single",
51182
+ optional: false
51183
+ }],
50618
51184
  "webrtcSession.addIceCandidate": [{
50619
51185
  name: "deviceId",
50620
51186
  form: "single",
@@ -51352,7 +51918,7 @@ var PreviewTextField = string().max(200);
51352
51918
  * Whether the notification's preview is a STILL or a short animation.
51353
51919
  *
51354
51920
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
51355
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
51921
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
51356
51922
  * night reads better as three seconds of motion than as one frame of it. Both
51357
51923
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
51358
51924
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -51490,6 +52056,7 @@ TimelapseRuleInputSchema.extend({
51490
52056
  createdAt: number(),
51491
52057
  updatedAt: number()
51492
52058
  });
52059
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
51493
52060
  object({
51494
52061
  /**
51495
52062
  * Fraction of the box's own size added on EACH side before cutting.