@camstack/addon-provider-rademacher 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
@@ -983,7 +983,7 @@ var Rademacher = class {
983
983
  }
984
984
  };
985
985
  //#endregion
986
- //#region ../types/dist/event-category-C5xZWqz6.mjs
986
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
987
987
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
988
988
  EventCategory["SystemBoot"] = "system.boot";
989
989
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -1516,6 +1516,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
1516
1516
  */
1517
1517
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
1518
1518
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
1519
+ /**
1520
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
1521
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
1522
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
1523
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
1524
+ * for a camera with no attached sensor). Providers must not emit
1525
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
1526
+ * keeps it so (camera-grid is a named, deferred exception).
1527
+ */
1519
1528
  EventCategory["ProviderMotion"] = "provider.motion";
1520
1529
  EventCategory["ProviderDetection"] = "provider.detection";
1521
1530
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -6354,7 +6363,7 @@ var ZodIssueCode = {
6354
6363
  var ZodFirstPartyTypeKind;
6355
6364
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6356
6365
  //#endregion
6357
- //#region ../types/dist/sleep-gU6hqv4_.mjs
6366
+ //#region ../types/dist/sleep-CDCONfkt.mjs
6358
6367
  /**
6359
6368
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6360
6369
  * window to float samples (D455).
@@ -8397,7 +8406,7 @@ function errMsg(err) {
8397
8406
  return String(err);
8398
8407
  }
8399
8408
  //#endregion
8400
- //#region ../types/dist/composition-Dq42XWp0.mjs
8409
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
8401
8410
  /**
8402
8411
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8403
8412
  *
@@ -8451,21 +8460,20 @@ function portable(target) {
8451
8460
  }
8452
8461
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
8453
8462
  /**
8454
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
8455
- * valutatore puro del suo FRONTE.
8463
+ * THE table "which boolean of this device type counts as HIGH", and the
8464
+ * pure evaluator of its EDGE.
8456
8465
  *
8457
- * Viveva dentro il builtin virtual-doorbell
8458
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
8459
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
8460
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
8461
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
8462
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
8463
- * SPOSTA qui e il doorbell la ri-esporta.
8466
+ * ONE table for everyone who asks "is this device HIGH?": the
8467
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
8468
+ * sensor markers, the orchestrator's camera-sensors bridge and
8469
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
8470
+ * A second copy would diverge at the first cap added, and the symptom — "the
8471
+ * sensor rings the doorbell but does not record" — is exactly D62.
8464
8472
  *
8465
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
8466
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
8467
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
8468
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
8473
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
8474
+ * two must not be unified: that one answers "what is the state WORD for a
8475
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
8476
+ * boolean's EDGE counts". Deliberately different vocabularies.
8469
8477
  */
8470
8478
  /**
8471
8479
  * Known binary / switch source caps → the boolean slice field whose
@@ -10074,22 +10082,22 @@ var CLASS_MAP_MACRO_TARGETS = [
10074
10082
  "package"
10075
10083
  ];
10076
10084
  /**
10077
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
10078
- * un operatore può selezionare.
10085
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
10086
+ * an operator can select.
10079
10087
  *
10080
- * Sono le tre offerte dallo step `object-detection`
10088
+ * They are the three offered by the `object-detection` step
10081
10089
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
10082
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
10083
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
10084
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
10085
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
10090
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
10091
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
10092
+ * `package-detection`, whose enablement is driven by zones, and offering the
10093
+ * same word twice has already made an operator turn on the COCO proxy
10086
10094
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
10087
10095
  *
10088
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
10089
- * dello step e una seconda volta come union `FirstLevelMacro`
10090
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
10091
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
10092
- * successiva.
10096
+ * ONE list. Before today the same three were hand-written in the step's offer
10097
+ * and a second time as the union `FirstLevelMacro`
10098
+ * (`types/detection.ts`); a third copy for the recording trigger
10099
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
10100
+ * invisible.
10093
10101
  */
10094
10102
  var FIRST_LEVEL_MACRO_CLASSES = [
10095
10103
  "person",
@@ -10154,17 +10162,17 @@ var RecordingStorageModeSchema = _enum([
10154
10162
  "on-device-decision"
10155
10163
  ]);
10156
10164
  /**
10157
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
10158
- * tre offerte dallo step `object-detection`, da UNA lista
10165
+ * The macro classes that can open a recording window — the same
10166
+ * three offered by the `object-detection` step, from ONE list
10159
10167
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
10160
10168
  */
10161
10169
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
10162
10170
  /**
10163
- * True quando `values` non ripete un elemento.
10171
+ * True when `values` does not repeat an element.
10164
10172
  *
10165
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
10166
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
10167
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
10173
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
10174
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
10175
+ * would count its windows twice in `segmentMissedByMs`.
10168
10176
  */
10169
10177
  var noDuplicates = (values) => new Set(values).size === values.length;
10170
10178
  /** Which detectors trigger an `events`-mode band. */
@@ -10172,34 +10180,34 @@ var RecordingTriggersSchema = object({
10172
10180
  motion: boolean().optional(),
10173
10181
  audioThresholdDbfs: number().optional(),
10174
10182
  /**
10175
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
10176
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
10177
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
10178
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
10183
+ * The macro classes whose detection opens a window. ABSENT = the source
10184
+ * is not listened to; an EMPTY array is rejected, because "events band, object
10185
+ * trigger on, no class" is the same shape "enabled and records
10186
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
10179
10187
  *
10180
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
10181
- * quelle che hanno attraversato `enabledMacroClasses`, i
10182
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
10183
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
10184
- * finestre — vedi `recorder/object-trigger.ts`.
10188
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
10189
+ * those that went through `enabledMacroClasses`, the
10190
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
10191
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
10192
+ * windows — see `recorder/object-trigger.ts`.
10185
10193
  */
10186
10194
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
10187
10195
  /**
10188
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
10189
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
10196
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
10197
+ * is not listened to; an empty array is rejected for the same reason as
10190
10198
  * `objectClasses`.
10191
10199
  *
10192
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
10193
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
10194
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
10195
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
10196
- * device (D12) — mai un elenco globale di cap.
10200
+ * These are SOURCE device ids, not cameras: the band names them, so the
10201
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
10202
+ * does no RPC. The OFFER from which the operator picks them is another question, and
10203
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
10204
+ * device (D12) — never a global list of caps.
10197
10205
  *
10198
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
10199
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
10200
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
10201
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
10202
- * registrare.
10206
+ * What "high" means depends on the device TYPE and is not decided here:
10207
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
10208
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
10209
+ * the level: a contact found already open at runner restart does not
10210
+ * record.
10203
10211
  */
10204
10212
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
10205
10213
  });
@@ -11276,7 +11284,7 @@ var DecoderSessionConfigSchema = object({
11276
11284
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
11277
11285
  * thing: the logging settings document on the `system` cap. Two authorities
11278
11286
  * over the values is the exact defect
11279
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
11287
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
11280
11288
  * remove; re-introducing it from the cure side would be grotesque.
11281
11289
  *
11282
11290
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -12987,7 +12995,7 @@ var BrokerStatusEnum = _enum([
12987
12995
  "unreachable",
12988
12996
  "error"
12989
12997
  ]);
12990
- var BrokerInfoSchema$1 = object({
12998
+ var BrokerInfoSchema = object({
12991
12999
  /** Stable broker id. Persisted; survives addon restarts. */
12992
13000
  id: string(),
12993
13001
  /** Addon id of the provider that OWNS this broker.
@@ -13120,7 +13128,7 @@ var GetStateInputSchema = object({
13120
13128
  * HA: entity_id (returns the cached entity state). */
13121
13129
  key: string()
13122
13130
  });
13123
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
13131
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
13124
13132
  kind: "mutation",
13125
13133
  auth: "admin"
13126
13134
  }), method(RemoveInputSchema, _void(), {
@@ -14831,7 +14839,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
14831
14839
  *
14832
14840
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
14833
14841
  * was wrong — corrected 2026-08-26 after the hop map
14834
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
14842
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
14835
14843
  * There is **no Zod parse at all** between the door and the engine: the
14836
14844
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
14837
14845
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -15807,7 +15815,17 @@ var SiteZoneSchema = object({
15807
15815
  var ProviderStatusSchema = object({
15808
15816
  connected: boolean(),
15809
15817
  deviceCount: number(),
15810
- error: string().optional()
15818
+ error: string().optional(),
15819
+ /**
15820
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
15821
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
15822
+ * which every provider bundles, so only a provider BUILT from D696-amended
15823
+ * code says it. ABSENT means an older provider that may still write it (raw
15824
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
15825
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
15826
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
15827
+ */
15828
+ motionSliceWriter: literal("orchestrator").optional()
15811
15829
  });
15812
15830
  object({
15813
15831
  externalId: string(),
@@ -16686,109 +16704,10 @@ method(object({
16686
16704
  deviceIds: array(number()).readonly(),
16687
16705
  caps: array(string()).readonly().optional()
16688
16706
  }), record(string(), record(string(), unknown().nullable())));
16689
- /**
16690
- * Doorbell button cap. Two kinds of providers coexist behind this cap
16691
- * name (same pattern as `snapshot`):
16692
- *
16693
- * - **Native** providers: registered per-device by device-driver
16694
- * addons via `ctx.registerNativeCap` — either on a
16695
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
16696
- * or directly on the camera (Reolink registers at camera level).
16697
- * Emits an `onPressed` event every time the firmware pushes a
16698
- * ring; status tracks the last press and a pressCount since start
16699
- * (diagnostic).
16700
- *
16701
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
16702
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
16703
- * device (contact / switch / event-emitter …) into a doorbell for
16704
- * a camera. `defaultActive: false` — the operator explicitly binds
16705
- * it per camera in the device-bindings UI, then picks the source
16706
- * device + trigger in the per-device settings.
16707
- *
16708
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
16709
- * — subscribers listening at the camera level receive ring events
16710
- * with `via[]` populated. No code on the parent needed.
16711
- */
16712
- var DoorbellStatusSchema = object({
16713
- /** Ms epoch of the last press. null = never observed since this provider started. */
16714
- lastPressedAt: number().nullable(),
16715
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
16716
- pressCountSinceStart: number()
16717
- });
16718
- var DoorbellPressEventSchema = object({
16719
- deviceId: number(),
16720
- timestamp: number()
16721
- });
16722
- /**
16723
- * The `doorbell-source` extension slot's editable value (D648): the camera's
16724
- * virtual-doorbell trigger devices, exactly what the wrapper's
16725
- * `doorbellSources` persists (as `{ deviceId }` records).
16726
- */
16727
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
16728
- /**
16729
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
16730
- * doorbell, owned by the `virtual-doorbell` wrapper over its
16731
- * `doorbellSources` store (D648). A source rings when one of its
16732
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
16733
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
16734
- * reports it, it never writes it.
16735
- */
16736
- var DOORBELL_SOURCE_SLOT = {
16737
- id: "doorbell-source",
16738
- label: "Doorbell trigger devices",
16739
- 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.",
16740
- shape: "association",
16741
- hostDeviceTypes: [DeviceType.Camera],
16742
- sourceCaps: SOURCE_CAPS,
16743
- cardinality: "many",
16744
- value: DoorbellSourceSlotValueSchema
16745
- };
16746
- var doorbellCapability = {
16747
- name: "doorbell",
16748
- scope: "device",
16749
- deviceNative: true,
16750
- mode: "singleton",
16751
- kind: "wrapper",
16752
- defaultActive: false,
16753
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
16754
- extensionSlots: [DOORBELL_SOURCE_SLOT],
16755
- methods: {},
16756
- events: {
16757
- /**
16758
- * Fires once per physical press. Reolink delivers via Baichuan
16759
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
16760
- * release/duration — it's a pulse.
16761
- */
16762
- onPressed: {
16763
- data: DoorbellPressEventSchema,
16764
- fromState: {
16765
- field: "lastPressedAt",
16766
- on: "advance"
16767
- }
16768
- } },
16769
- status: {
16770
- schema: DoorbellStatusSchema,
16771
- kind: "push"
16772
- },
16773
- /**
16774
- * Runtime-state slice — last press timestamp + lifetime press count.
16775
- * Mirrored by the kernel and readable via
16776
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
16777
- * without subscribing.
16778
- */
16779
- runtimeState: DoorbellStatusSchema,
16780
- /**
16781
- * 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.
16782
- *
16783
- * See `RuntimeStateDurability`. Enforced by
16784
- * `scripts/check-runtime-state-durability.ts`.
16785
- */
16786
- durability: "restored"
16787
- };
16788
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
16789
- DeviceType.Camera, DeviceType.Camera;
16707
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
16708
+ DeviceType.Camera;
16790
16709
  /** A slot's editable value, discriminated on `slot`. */
16791
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
16710
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
16792
16711
  DeviceType.Camera;
16793
16712
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
16794
16713
  state: literal("unreachable"),
@@ -16825,10 +16744,11 @@ var ExtensionSlotSourceSchema = object({
16825
16744
  });
16826
16745
  /**
16827
16746
  * A DIFFERENT authority that gates whether the slot's sources do anything —
16828
- * reported read-only, named, never written through this contract (D62). The
16829
- * virtual doorbell's sources ring only while the wrapper is bound to the
16830
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
16831
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
16747
+ * reported read-only, named, never written through this contract (D62) — e.g.
16748
+ * a slot whose sources act only while a wrapper is bound to the host, a
16749
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
16750
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
16751
+ * not be read; it is not "inactive" (D315).
16832
16752
  */
16833
16753
  var ExtensionSlotActivationSchema = object({
16834
16754
  state: _enum([
@@ -16844,7 +16764,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
16844
16764
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
16845
16765
  slotRef: string(),
16846
16766
  slot: ExtensionSlotIdSchema,
16847
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
16767
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
16848
16768
  authority: string(),
16849
16769
  activation: ExtensionSlotActivationSchema.nullable(),
16850
16770
  value: ExtensionSlotValueSchema,
@@ -17122,7 +17042,7 @@ method(object({
17122
17042
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
17123
17043
  * ends in a log line, and a log line is the thing the operator asked to stop
17124
17044
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
17125
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
17045
+ * 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
17126
17046
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
17127
17047
  * media blackout were both diagnosed. The counters stay; this is where they can
17128
17048
  * be READ.
@@ -18498,7 +18418,7 @@ var BrokerStatusSchema$1 = _enum([
18498
18418
  "unreachable",
18499
18419
  "tls-error"
18500
18420
  ]);
18501
- var BrokerInfoSchema = object({
18421
+ var BrokerInfoSchema$1 = object({
18502
18422
  id: string(),
18503
18423
  name: string(),
18504
18424
  url: string(),
@@ -18561,7 +18481,7 @@ var StatusSchema = object({
18561
18481
  brokerCount: number(),
18562
18482
  embeddedRunning: boolean()
18563
18483
  });
18564
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
18484
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
18565
18485
  kind: "mutation",
18566
18486
  auth: "admin"
18567
18487
  }), method(IdInputSchema, _void(), {
@@ -20775,78 +20695,16 @@ var NcRuleInputSchema = object({
20775
20695
  */
20776
20696
  confirm: NcConfirmSchema.optional(),
20777
20697
  /**
20778
- * WAIT for face/plate recognition before saying anything.
20779
- *
20780
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
20781
- * send; the identity is neither. A face is confirmed after `confirmFrames`
20782
- * agreeing observations — p50 **11.4 s** after the track was first seen,
20783
- * measured on this hub — and an `immediate` rule enqueues on the first object
20784
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
20785
- * immediate path, and no amount of media re-resolution fixes a sentence.
20786
- *
20787
- * Only two honest answers exist, and this flag picks between them. It has
20788
- * effect ONLY on a rule that declares a recognition scope
20789
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
20790
- * other rule there is nothing to wait for and the flag is inert.
20791
- *
20792
- * | value | what happens |
20793
- * | --- | --- |
20794
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
20795
- * | 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) |
20796
- *
20797
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
20798
- * on the addon cap path, and absent has to keep meaning exactly what every
20799
- * rule authored before this field meant.
20800
- *
20801
- * The cost of `true` is stated here because the editor states it too: a rule
20802
- * that waits also inherits track-close SEMANTICS — its `zones` condition
20803
- * tests every zone the track visited and a `crossing` condition can no longer
20804
- * be satisfied, because a closed track carries no crossing.
20698
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
20699
+ * seconds; the rule sends ONE message when the window closes — early, once every
20700
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
20701
+ * the rule matched, with one mosaic tile per subject.
20702
+ * Absent = plain immediate (one message per track, at the first match).
20703
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
20704
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
20705
+ * path does not run Zod defaults.
20805
20706
  */
20806
- waitForEnhancement: boolean().optional(),
20807
- /**
20808
- * GROUP a burst of subjects into ONE notification that grows.
20809
- *
20810
- * Seconds of quiet after the last matching subject before the burst is
20811
- * considered over. While it is open, the first subject enqueues immediately —
20812
- * **exactly as today, with no added latency** — and every real growth (a new
20813
- * subject, or a name confirmed on one already in it) REPLACES that
20814
- * notification with an updated one naming everybody. The push carries the
20815
- * group's own coalescing tag, so the phone replaces rather than stacks.
20816
- *
20817
- * `0` / absent = off, and off is today's behaviour byte for byte.
20818
- *
20819
- * ### Why an idle cutoff and not a window
20820
- *
20821
- * The measured seven-person arrival on device 590 spans 110 s with every
20822
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
20823
- * idle cutoff holds it as one and ends it when the arrival actually ends.
20824
- * 30 s is a widely shipped value for the same decision.
20825
- *
20826
- * ### What it replaces
20827
- *
20828
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
20829
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
20830
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
20831
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
20832
- * A group collapses the same volume by MERGING, so the cooldown becomes a
20833
- * budget over GROUPS — which is what it always meant — and a growth is never
20834
- * throttled by the window its own first member spent.
20835
- *
20836
- * ### Interaction with {@link waitForEnhancement}
20837
- *
20838
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
20839
- * TRACK CLOSE, so with both set the group is opened by the first member to
20840
- * CLOSE — already carrying its name — and grows as later members close. That
20841
- * is later, and complete. With grouping alone the group opens on the first
20842
- * object event and picks up names as they are confirmed, through the growth
20843
- * path. Neither combination fires twice for one subject.
20844
- *
20845
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
20846
- * on the addon cap path, so absent must keep meaning what it meant before this
20847
- * field existed.
20848
- */
20849
- groupIdleSec: number().int().min(0).max(600).optional()
20707
+ groupingSec: number().int().min(5).max(60).optional()
20850
20708
  });
20851
20709
  /**
20852
20710
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -20894,9 +20752,10 @@ var NcRuleClearableKeySchema = _enum([
20894
20752
  "targetUsers",
20895
20753
  "snoozeOptions",
20896
20754
  "snoozeAllowGlobal",
20897
- "waitForEnhancement",
20898
20755
  "actions",
20899
20756
  "confirm",
20757
+ "groupingSec",
20758
+ "waitForEnhancement",
20900
20759
  "groupIdleSec"
20901
20760
  ]);
20902
20761
  var NcRuleUpdateInputSchema = object({
@@ -20918,9 +20777,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20918
20777
  */
20919
20778
  disabledTargetIds: array(string()).default([])
20920
20779
  });
20780
+ /**
20781
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20782
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
20783
+ * job is not an open state, and the alarm stays instant.
20784
+ */
20785
+ var NcStateSummarySectionIdSchema = _enum([
20786
+ "device-state",
20787
+ "streams",
20788
+ "battery",
20789
+ "consumables",
20790
+ "tanks",
20791
+ "detection-blind",
20792
+ "nodes",
20793
+ "addons",
20794
+ "updates"
20795
+ ]);
20921
20796
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
20922
20797
  var NcStateSummaryPreviewSectionSchema = object({
20923
- id: string(),
20798
+ id: NcStateSummarySectionIdSchema,
20924
20799
  status: _enum(["read", "unavailable"]),
20925
20800
  items: number().int().nonnegative(),
20926
20801
  reason: string().optional()
@@ -20930,7 +20805,7 @@ var NcStateSummaryPreviewSectionSchema = object({
20930
20805
  * a `rule` split (no `section`), one section's on a `section` split.
20931
20806
  */
20932
20807
  var NcStateSummaryPreviewRowSchema = object({
20933
- section: string().optional(),
20808
+ section: NcStateSummarySectionIdSchema.optional(),
20934
20809
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
20935
20810
  title: string(),
20936
20811
  text: string(),
@@ -21367,6 +21242,29 @@ object({
21367
21242
  firstAt: number(),
21368
21243
  lastAt: number()
21369
21244
  });
21245
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
21246
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
21247
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
21248
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
21249
+ var NcAlarmModeDelaysListSchema = array(object({
21250
+ mode: AlarmArmModeSchema,
21251
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
21252
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
21253
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
21254
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
21255
+ var NcAlarmModeDelaysEditListSchema = array(object({
21256
+ mode: AlarmArmModeSchema,
21257
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21258
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21259
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
21260
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
21261
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
21262
+ var NcAlarmNonBlockingEditSchema = object({
21263
+ mode: AlarmArmModeSchema,
21264
+ deviceId: number().int().positive(),
21265
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
21266
+ nonBlocking: boolean()
21267
+ });
21370
21268
  /**
21371
21269
  * The per-mode lists, at most one per mode. Two lists for one mode have no
21372
21270
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -21375,10 +21273,10 @@ object({
21375
21273
  var NcAlarmNonBlockingListSchema = array(object({
21376
21274
  mode: AlarmArmModeSchema,
21377
21275
  deviceIds: array(number().int()).max(200)
21378
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
21276
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
21379
21277
  /**
21380
- * The three durations the panel's state machine runs on, who hears about its
21381
- * transitions, and which openings each mode tolerates.
21278
+ * The three durations — global, and per mode since D697 — the panel's state
21279
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
21382
21280
  *
21383
21281
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
21384
21282
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -21388,15 +21286,15 @@ var NcAlarmNonBlockingListSchema = array(object({
21388
21286
  */
21389
21287
  var NcAlarmSettingsSchema = object({
21390
21288
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
21391
- exitDelaySec: number().int().min(0).max(600),
21289
+ exitDelaySec: NcAlarmDelaySecSchema,
21392
21290
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
21393
- entryDelaySec: number().int().min(0).max(600),
21291
+ entryDelaySec: NcAlarmDelaySecSchema,
21394
21292
  /**
21395
21293
  * How long `triggered` lasts before the panel re-arms itself.
21396
21294
  * **0 = until an operator disarms it** — the behaviour before this field
21397
21295
  * existed, and therefore what an untouched install keeps doing.
21398
21296
  */
21399
- triggeredDurationSec: number().int().min(0).max(3600),
21297
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
21400
21298
  /**
21401
21299
  * Deprecated by D630 — every transition is announced. Parsed, never read;
21402
21300
  * remove after one release. Optional so an older admin's patch (which still
@@ -21419,17 +21317,30 @@ var NcAlarmSettingsSchema = object({
21419
21317
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
21420
21318
  * parses as "every opening blocks" — the behaviour it was written under.
21421
21319
  */
21422
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
21320
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
21321
+ /**
21322
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
21323
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
21324
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
21325
+ */
21326
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
21423
21327
  });
21424
21328
  /**
21425
21329
  * Every field optional — a tab edits one control at a time.
21426
21330
  *
21427
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
21428
- * remove an inner `.default()`, so a patch that never named the field would
21429
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
21430
- * (the same trap {@link NcRulePatchSchema} documents).
21331
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
21332
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
21333
+ * named the field would parse to `[]` and wipe every mode's list on an
21334
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
21335
+ * `modeDelays` means EDITS, not the stored overrides.
21431
21336
  */
21432
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
21337
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
21338
+ nonBlocking: NcAlarmNonBlockingListSchema,
21339
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
21340
+ modeDelays: NcAlarmModeDelaysEditListSchema,
21341
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
21342
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
21343
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
21433
21344
  /**
21434
21345
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
21435
21346
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -21529,6 +21440,28 @@ var NcAlarmConfigSchema = object({
21529
21440
  */
21530
21441
  live: NcAlarmLiveSchema.optional()
21531
21442
  });
21443
+ var NcAlarmSensorReadingSchema = _enum([
21444
+ "open",
21445
+ "closed",
21446
+ "unknown",
21447
+ "not-opening"
21448
+ ]);
21449
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
21450
+ var NcAlarmSensorStateSchema = object({
21451
+ deviceId: number().int().positive(),
21452
+ reading: NcAlarmSensorReadingSchema,
21453
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
21454
+ state: string().nullable(),
21455
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
21456
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
21457
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
21458
+ online: boolean().nullable()
21459
+ });
21460
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
21461
+ var NcAlarmSensorsSchema = object({
21462
+ sensors: array(NcAlarmSensorStateSchema),
21463
+ readAt: number().int().nonnegative()
21464
+ });
21532
21465
  /**
21533
21466
  * ONE rule's demand on ONE camera's clip ring.
21534
21467
  *
@@ -21619,7 +21552,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
21619
21552
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
21620
21553
  kind: "mutation",
21621
21554
  auth: "admin"
21622
- });
21555
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
21623
21556
  /**
21624
21557
  * Zod schemas for persisted record types.
21625
21558
  *
@@ -21966,12 +21899,26 @@ var CameraSensorRefSchema = object({
21966
21899
  function cameraSensorRefKey(ref) {
21967
21900
  return `${ref.addonId}/${ref.stableId}`;
21968
21901
  }
21969
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
21970
- var CameraSensorsModeSchema = _enum(["in-addition"]);
21971
- var CameraSensorsConfigSchema = object({
21972
- mode: CameraSensorsModeSchema,
21973
- sensors: array(CameraSensorRefSchema).min(1).max(8)
21974
- }).superRefine((value, ctx) => {
21902
+ /**
21903
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
21904
+ * `replace`: its motion is the camera's, and while one is READY the camera's
21905
+ * own motion no longer counts on its own. `confirm`: while one is READY the
21906
+ * camera's own motion counts only while a confirm sensor is active — with or
21907
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
21908
+ */
21909
+ var CameraSensorModeSchema = _enum([
21910
+ "in-addition",
21911
+ "confirm",
21912
+ "replace"
21913
+ ]);
21914
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
21915
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
21916
+ /**
21917
+ * A camera's attached sensors. A CS-1 row carried an envelope
21918
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
21919
+ * what the write stores (D672 rule 3), so it is never written again.
21920
+ */
21921
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
21975
21922
  const seen = /* @__PURE__ */ new Set();
21976
21923
  value.sensors.forEach((ref, index) => {
21977
21924
  const key = cameraSensorRefKey(ref);
@@ -21983,39 +21930,41 @@ var CameraSensorsConfigSchema = object({
21983
21930
  seen.add(key);
21984
21931
  });
21985
21932
  });
21986
- var RefFields = {
21933
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
21934
+ var AttachmentFields = {
21987
21935
  addonId: string(),
21988
- stableId: string()
21936
+ stableId: string(),
21937
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
21989
21938
  };
21990
21939
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
21991
21940
  object({
21992
- ...RefFields,
21941
+ ...AttachmentFields,
21993
21942
  state: literal("ready"),
21994
21943
  deviceId: number(),
21995
21944
  name: string(),
21996
21945
  caps: array(string()).readonly()
21997
21946
  }),
21998
21947
  object({
21999
- ...RefFields,
21948
+ ...AttachmentFields,
22000
21949
  state: literal("offline"),
22001
21950
  deviceId: number(),
22002
21951
  name: string(),
22003
21952
  reason: _enum(["offline", "disabled"])
22004
21953
  }),
22005
21954
  object({
22006
- ...RefFields,
21955
+ ...AttachmentFields,
22007
21956
  state: literal("missing"),
22008
21957
  reason: string()
22009
21958
  }),
22010
21959
  object({
22011
- ...RefFields,
21960
+ ...AttachmentFields,
22012
21961
  state: literal("unsupported"),
22013
21962
  deviceId: number(),
22014
21963
  name: string(),
22015
21964
  reason: string()
22016
21965
  }),
22017
21966
  object({
22018
- ...RefFields,
21967
+ ...AttachmentFields,
22019
21968
  state: literal("unreadable"),
22020
21969
  reason: string()
22021
21970
  })
@@ -22028,17 +21977,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
22028
21977
  * say.
22029
21978
  */
22030
21979
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
21980
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
21981
+ var CameraOwnMotionSchema = _enum([
21982
+ "always",
21983
+ "when-confirmed",
21984
+ "never"
21985
+ ]);
21986
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
21987
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
21988
+ /**
21989
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
21990
+ * never the effective value. The camera's `motion` slice is the effective one,
21991
+ * so a view of the camera's own row reads this.
21992
+ * - `atMs`: when the bridge received the camera's last own edge.
21993
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
21994
+ * AND it is younger than the window the bridge counts the camera's own motion
21995
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
21996
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
21997
+ * within the window; a status read is a snapshot, so a live view re-asks.
21998
+ * Absent = this orchestrator has not received the camera's own motion since it
21999
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
22000
+ */
22001
+ var CameraRawLevelSchema = object({
22002
+ detected: boolean(),
22003
+ atMs: number()
22004
+ });
22031
22005
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
22032
- object({ state: literal("not-configured") }),
22006
+ object({
22007
+ state: literal("not-configured"),
22008
+ cameraLevel: CameraRawLevelSchema.optional()
22009
+ }),
22033
22010
  object({
22034
22011
  state: literal("unreadable"),
22035
- reason: string()
22012
+ reason: string(),
22013
+ cameraLevel: CameraRawLevelSchema.optional()
22036
22014
  }),
22037
22015
  object({
22038
22016
  state: literal("configured"),
22039
- mode: CameraSensorsModeSchema,
22017
+ cameraLevel: CameraRawLevelSchema.optional(),
22040
22018
  sensors: array(CameraSensorAttachmentSchema).readonly(),
22041
- notForwarded: CameraSensorsNotForwardedSchema.optional()
22019
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
22020
+ cameraMotion: CameraOwnMotionSchema.optional(),
22021
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
22022
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
22042
22023
  })
22043
22024
  ]);
22044
22025
  Object.freeze({
@@ -22723,14 +22704,14 @@ var TrackSchema = object({
22723
22704
  * `derive-returned-null tile=standin`,
22724
22705
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
22725
22706
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
22726
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
22707
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
22727
22708
  * tile is a face/plate stand-in, a raster crop, or an icon.
22728
22709
  *
22729
22710
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
22730
22711
  * the TILE ranked below native, so a track whose thumbnail landed natively
22731
22712
  * while its key frame missed carried no reason at all — three of the four
22732
22713
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
22733
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
22714
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
22734
22715
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
22735
22716
  * lastFrame copy source`), so its absence is now on this line whatever the
22736
22717
  * tile ended up being.
@@ -22817,7 +22798,7 @@ var MotionEventSchema = object({
22817
22798
  /**
22818
22799
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
22819
22800
  * first entry is always `0`) of every genuine off→on transition the
22820
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
22801
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
22821
22802
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
22822
22803
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
22823
22804
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -23341,6 +23322,7 @@ var KeyEventSchema = object({
23341
23322
  bestEventId: string(),
23342
23323
  /** Track lifetime in ms (lastSeen - firstSeen). */
23343
23324
  windowMs: number().optional(),
23325
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
23344
23326
  ...TrackFlagFields,
23345
23327
  ...TrackRetrainFields
23346
23328
  });
@@ -25269,8 +25251,10 @@ var RunnerCameraConfigSchema = object({
25269
25251
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
25270
25252
  * analyzer providers) running on decoded frames in this runner.
25271
25253
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
25272
- * analytics). The provider emits ProviderMotion
25273
- * events; the orchestrator forwards to `reportMotion`.
25254
+ * analytics). The provider emits its raw push as `ProviderMotion`
25255
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
25256
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
25257
+ * `reportMotion`.
25274
25258
  */
25275
25259
  motionSources: MotionSourcesSchema.default(["analyzer"]),
25276
25260
  /**
@@ -25447,7 +25431,15 @@ var RunnerLocalLoadSchema = object({
25447
25431
  hasGpu: boolean(),
25448
25432
  inferenceBackend: string().optional(),
25449
25433
  cpuCores: number().optional()
25450
- })
25434
+ }),
25435
+ /**
25436
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
25437
+ * runner never writes it. ABSENT = a runner older than D696, which still
25438
+ * writes the slice from its phase machine; the orchestrator does not write
25439
+ * while any runner node is absent-or-unanswered, so one slice never has two
25440
+ * writers.
25441
+ */
25442
+ motionSliceWriter: literal("orchestrator").optional()
25451
25443
  });
25452
25444
  /**
25453
25445
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -28112,7 +28104,7 @@ var ClipPlaybackSchema = object({
28112
28104
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
28113
28105
  * time the camera is awake for its own reasons — is deliberately not a member:
28114
28106
  * it was proposed, it is free on the battery, and the operator declined it on
28115
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
28107
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
28116
28108
  * D558 "Considered and not taken").
28117
28109
  */
28118
28110
  var ClipWakeSchema = _enum(["authorised"]);
@@ -28373,7 +28365,7 @@ DeviceType.Camera, method(object({
28373
28365
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
28374
28366
  * assumed the answer was a fan-out over everything a camera has. The
28375
28367
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
28376
- * solo"* — so the list is asked of one provider at a time and there is
28368
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
28377
28369
  * nothing to filter out of it.
28378
28370
  */
28379
28371
  provider: string().min(1)
@@ -30968,6 +30960,70 @@ onStatusChanged: { data: object({
30968
30960
  * whether persisting is worth a SQLite commit. */
30969
30961
  volatileStateFields: ["lastChangedAt"]
30970
30962
  };
30963
+ var DoorbellStatusSchema = object({
30964
+ /** Ms epoch of the last press. null = never observed since this provider started. */
30965
+ lastPressedAt: number().nullable(),
30966
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
30967
+ pressCountSinceStart: number()
30968
+ });
30969
+ var DoorbellPressEventSchema = object({
30970
+ deviceId: number(),
30971
+ timestamp: number()
30972
+ });
30973
+ /**
30974
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
30975
+ * they are the same cap:
30976
+ *
30977
+ * - **Native** providers, registered per device by a driver addon through
30978
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
30979
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
30980
+ * camera level). They emit `onPressed` on every firmware ring.
30981
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
30982
+ * the cap, its `lastPressedAt` rising from the sources the operator
30983
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
30984
+ * from that field's advance (`fromState`).
30985
+ *
30986
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
30987
+ */
30988
+ var doorbellCapability = {
30989
+ name: "doorbell",
30990
+ scope: "device",
30991
+ deviceNative: true,
30992
+ mode: "singleton",
30993
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
30994
+ methods: {},
30995
+ events: {
30996
+ /**
30997
+ * Fires once per physical press. Reolink delivers via Baichuan
30998
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
30999
+ * release/duration — it's a pulse.
31000
+ */
31001
+ onPressed: {
31002
+ data: DoorbellPressEventSchema,
31003
+ fromState: {
31004
+ field: "lastPressedAt",
31005
+ on: "advance"
31006
+ }
31007
+ } },
31008
+ status: {
31009
+ schema: DoorbellStatusSchema,
31010
+ kind: "push"
31011
+ },
31012
+ /**
31013
+ * Runtime-state slice — last press timestamp + lifetime press count.
31014
+ * Mirrored by the kernel and readable via
31015
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
31016
+ * without subscribing.
31017
+ */
31018
+ runtimeState: DoorbellStatusSchema,
31019
+ /**
31020
+ * 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.
31021
+ *
31022
+ * See `RuntimeStateDurability`. Enforced by
31023
+ * `scripts/check-runtime-state-durability.ts`.
31024
+ */
31025
+ durability: "restored"
31026
+ };
30971
31027
  /**
30972
31028
  * Enum-state sensor — a string value picked from a finite option set.
30973
31029
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -33112,9 +33168,9 @@ var MotionStatusSchema = object({
33112
33168
  /** Ms epoch of the last detected-true observation. Null if never detected. */
33113
33169
  lastDetectedAt: number().nullable(),
33114
33170
  /**
33115
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
33116
- * `null` while false and on every `Sensor` device (D475) — see that
33117
- * constant's doc for the one-authority rule.
33171
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
33172
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
33173
+ * device (D475) — see that constant's doc for the one-authority rule.
33118
33174
  *
33119
33175
  * ## Reading this field still arms nothing
33120
33176
  *
@@ -33132,34 +33188,31 @@ var MotionStatusSchema = object({
33132
33188
  * `addon-export-alexa/src/motion-clear-hold.ts` and
33133
33189
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
33134
33190
  *
33135
- * ## Who writes it
33136
- *
33137
- * - **Cameras** — the runner's phase machine, `active → watching` on
33138
- * `cooldown_expired`, which then writes this slice with
33139
- * `detected: false` (`handlePhaseChanged` in
33140
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
33141
- * matters most for the sources that only ever push a rising one:
33142
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
33143
- * a false.
33144
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
33145
- * provider pushes the false itself, from the upstream system's own
33146
- * state change. No phase machine is involved.
33147
- *
33148
- * ### The phase machine is CANONICAL, not sole — and that is a defect
33149
- *
33150
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
33151
- * phase machine is the sole writer for a camera. It is not.
33152
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
33153
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
33154
- * Hikvision's comment says why: it read THIS docblock, agreed the
33155
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
33156
- * two authorities can disagree about one slice, which this repo
33157
- * forbids, and the doc said otherwise — which is worse than saying
33158
- * nothing, because it reads as verification.
33159
- *
33160
- * This predates D475 and is not fixed there: the fix touches every
33161
- * camera provider. Recorded in D475's Consequences. Do not restore the
33162
- * "sole writer" wording without also removing the other writers.
33191
+ * ## Who writes it (D696)
33192
+ *
33193
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
33194
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
33195
+ * `camera-sensors/motion-slice.ts`), alongside the effective
33196
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
33197
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
33198
+ * device activity, as the camera's `motionSources` counts them. A source
33199
+ * that never sends a clear falls one window after its last `true`.
33200
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
33201
+ * writes this slice (not even a boot seed), and neither does the runner's
33202
+ * phase machine: its phase is "a session is attached" for every on-motion
33203
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
33204
+ * A provider's `isDetected` answers from the hub's slice.
33205
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
33206
+ * imports) — the provider pushes both edges itself, from the upstream
33207
+ * system's own state change. That is the sensor's own fact.
33208
+ *
33209
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
33210
+ * `motion` slice; each sensor writer is a named exemption.
33211
+ *
33212
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
33213
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
33214
+ * it, every provider seeded it at boot, and every session left it
33215
+ * `detected: true` after its detach.
33163
33216
  */
33164
33217
  autoClearAfterMs: number().nullable()
33165
33218
  });
@@ -33231,11 +33284,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
33231
33284
  */
33232
33285
  runtimeState: MotionStatusSchema,
33233
33286
  /**
33234
- * Runtime-state durability: **session** — every writer of this slice
33287
+ * Runtime-state durability: **session** — the writer of this slice
33235
33288
  * writes only on an EDGE, so a restored `detected: true` would stay
33236
33289
  * frozen until the next one instead of being corrected. The next edge
33237
- * re-publishes the real state. (On who the writers are, and why there
33238
- * is more than one, see `autoClearAfterMs` above.)
33290
+ * re-publishes the real state, and the orchestrator re-publishes every
33291
+ * camera when it starts writing (D696; on who writes it, see
33292
+ * `autoClearAfterMs` above).
33239
33293
  *
33240
33294
  * See `RuntimeStateDurability`. Enforced by
33241
33295
  * `scripts/check-runtime-state-durability.ts`.
@@ -35618,8 +35672,7 @@ var ptzAutotrackCapability = {
35618
35672
  deviceNative: true,
35619
35673
  mode: "singleton",
35620
35674
  /**
35621
- * Two kinds of provider behind one name, the same shape `snapshot` and
35622
- * `doorbell` use:
35675
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
35623
35676
  *
35624
35677
  * - **Native**: the camera's own firmware autotrack, registered per device by
35625
35678
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -35627,7 +35680,7 @@ var ptzAutotrackCapability = {
35627
35680
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
35628
35681
  * which follows a subject with `ptz.move` pulses driven by the detection
35629
35682
  * pipeline. `defaultActive: false` — the operator binds it per camera in
35630
- * the bindings UI, exactly as `virtual-doorbell` is bound.
35683
+ * the bindings UI.
35631
35684
  *
35632
35685
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
35633
35686
  * one switch for the function either way. A camera never has both driving its
@@ -36302,7 +36355,7 @@ var ReadGopBytesResultSchema = object({
36302
36355
  /**
36303
36356
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
36304
36357
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
36305
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
36358
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
36306
36359
  * a replay needs several seconds of native pixels, not one frame.
36307
36360
  *
36308
36361
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -39666,6 +39719,7 @@ var zoneRulesCapability = {
39666
39719
  */
39667
39720
  durability: "restored"
39668
39721
  };
39722
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
39669
39723
  /**
39670
39724
  * Accessory device helpers — shared across drivers.
39671
39725
  *
@@ -40725,13 +40779,14 @@ var BaseDeviceProvider = class extends BaseAddon {
40725
40779
  async getStatus() {
40726
40780
  const all = await this.ctx.kernel.devices?.getAll() ?? [];
40727
40781
  const summary = this.restoreFailureSummary();
40728
- if (summary === null) return {
40782
+ const base = {
40729
40783
  connected: true,
40730
- deviceCount: all.length
40784
+ deviceCount: all.length,
40785
+ motionSliceWriter: "orchestrator"
40731
40786
  };
40787
+ if (summary === null) return base;
40732
40788
  return {
40733
- connected: true,
40734
- deviceCount: all.length,
40789
+ ...base,
40735
40790
  error: summary
40736
40791
  };
40737
40792
  }
@@ -46167,6 +46222,12 @@ Object.freeze({
46167
46222
  addonId: null,
46168
46223
  access: "view"
46169
46224
  },
46225
+ "notificationRules.getAlarmSensors": {
46226
+ capName: "notification-rules",
46227
+ capScope: "system",
46228
+ addonId: null,
46229
+ access: "view"
46230
+ },
46170
46231
  "notificationRules.getClipRetentionAsks": {
46171
46232
  capName: "notification-rules",
46172
46233
  capScope: "system",
@@ -49745,6 +49806,11 @@ Object.freeze({
49745
49806
  }
49746
49807
  });
49747
49808
  Object.freeze({
49809
+ "accessories.getStatus": [{
49810
+ name: "deviceId",
49811
+ form: "single",
49812
+ optional: false
49813
+ }],
49748
49814
  "accessories.setChildHidden": [{
49749
49815
  name: "childDeviceId",
49750
49816
  form: "single",
@@ -49764,6 +49830,11 @@ Object.freeze({
49764
49830
  form: "single",
49765
49831
  optional: false
49766
49832
  }],
49833
+ "airQualitySensor.getStatus": [{
49834
+ name: "deviceId",
49835
+ form: "single",
49836
+ optional: false
49837
+ }],
49767
49838
  "alarmPanel.arm": [{
49768
49839
  name: "deviceId",
49769
49840
  form: "single",
@@ -49774,11 +49845,36 @@ Object.freeze({
49774
49845
  form: "single",
49775
49846
  optional: false
49776
49847
  }],
49848
+ "alarmPanel.getStatus": [{
49849
+ name: "deviceId",
49850
+ form: "single",
49851
+ optional: false
49852
+ }],
49777
49853
  "alarmPanel.trigger": [{
49778
49854
  name: "deviceId",
49779
49855
  form: "single",
49780
49856
  optional: false
49781
49857
  }],
49858
+ "ambientLightSensor.getStatus": [{
49859
+ name: "deviceId",
49860
+ form: "single",
49861
+ optional: false
49862
+ }],
49863
+ "audioAnalysis.applyDeviceSettingsPatch": [{
49864
+ name: "deviceId",
49865
+ form: "single",
49866
+ optional: false
49867
+ }],
49868
+ "audioAnalysis.getDeviceLiveContribution": [{
49869
+ name: "deviceId",
49870
+ form: "single",
49871
+ optional: false
49872
+ }],
49873
+ "audioAnalysis.getDeviceSettingsContribution": [{
49874
+ name: "deviceId",
49875
+ form: "single",
49876
+ optional: false
49877
+ }],
49782
49878
  "audioAnalysis.resolveDeviceSettings": [{
49783
49879
  name: "deviceId",
49784
49880
  form: "single",
@@ -49819,16 +49915,36 @@ Object.freeze({
49819
49915
  form: "single",
49820
49916
  optional: false
49821
49917
  }],
49918
+ "automationControl.getStatus": [{
49919
+ name: "deviceId",
49920
+ form: "single",
49921
+ optional: false
49922
+ }],
49822
49923
  "automationControl.trigger": [{
49823
49924
  name: "deviceId",
49824
49925
  form: "single",
49825
49926
  optional: false
49826
49927
  }],
49928
+ "battery.getStatus": [{
49929
+ name: "deviceId",
49930
+ form: "single",
49931
+ optional: false
49932
+ }],
49827
49933
  "battery.wakeForStream": [{
49828
49934
  name: "deviceId",
49829
49935
  form: "single",
49830
49936
  optional: false
49831
49937
  }],
49938
+ "binary.getStatus": [{
49939
+ name: "deviceId",
49940
+ form: "single",
49941
+ optional: false
49942
+ }],
49943
+ "brightness.getStatus": [{
49944
+ name: "deviceId",
49945
+ form: "single",
49946
+ optional: false
49947
+ }],
49832
49948
  "brightness.setBrightness": [{
49833
49949
  name: "deviceId",
49834
49950
  form: "single",
@@ -49844,6 +49960,26 @@ Object.freeze({
49844
49960
  form: "single",
49845
49961
  optional: false
49846
49962
  }],
49963
+ "cameraCredentials.getStatus": [{
49964
+ name: "deviceId",
49965
+ form: "single",
49966
+ optional: false
49967
+ }],
49968
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
49969
+ name: "deviceId",
49970
+ form: "single",
49971
+ optional: false
49972
+ }],
49973
+ "cameraGridLayout.getDeviceLiveContribution": [{
49974
+ name: "deviceId",
49975
+ form: "single",
49976
+ optional: false
49977
+ }],
49978
+ "cameraGridLayout.getDeviceSettingsContribution": [{
49979
+ name: "deviceId",
49980
+ form: "single",
49981
+ optional: false
49982
+ }],
49847
49983
  "cameraGridLayout.getLayout": [{
49848
49984
  name: "deviceId",
49849
49985
  form: "single",
@@ -49859,6 +49995,21 @@ Object.freeze({
49859
49995
  form: "single",
49860
49996
  optional: false
49861
49997
  }],
49998
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
49999
+ name: "deviceId",
50000
+ form: "single",
50001
+ optional: false
50002
+ }],
50003
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
50004
+ name: "deviceId",
50005
+ form: "single",
50006
+ optional: false
50007
+ }],
50008
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
50009
+ name: "deviceId",
50010
+ form: "single",
50011
+ optional: false
50012
+ }],
49862
50013
  "cameraStreams.getBrokerStreams": [{
49863
50014
  name: "deviceId",
49864
50015
  form: "single",
@@ -49884,6 +50035,16 @@ Object.freeze({
49884
50035
  form: "single",
49885
50036
  optional: false
49886
50037
  }],
50038
+ "carbonMonoxide.getStatus": [{
50039
+ name: "deviceId",
50040
+ form: "single",
50041
+ optional: false
50042
+ }],
50043
+ "climateControl.getStatus": [{
50044
+ name: "deviceId",
50045
+ form: "single",
50046
+ optional: false
50047
+ }],
49887
50048
  "climateControl.setFanMode": [{
49888
50049
  name: "deviceId",
49889
50050
  form: "single",
@@ -49924,16 +50085,41 @@ Object.freeze({
49924
50085
  form: "single",
49925
50086
  optional: false
49926
50087
  }],
50088
+ "color.getStatus": [{
50089
+ name: "deviceId",
50090
+ form: "single",
50091
+ optional: false
50092
+ }],
49927
50093
  "color.setColor": [{
49928
50094
  name: "deviceId",
49929
50095
  form: "single",
49930
50096
  optional: false
49931
50097
  }],
50098
+ "connectivity.getStatus": [{
50099
+ name: "deviceId",
50100
+ form: "single",
50101
+ optional: false
50102
+ }],
50103
+ "consumables.getStatus": [{
50104
+ name: "deviceId",
50105
+ form: "single",
50106
+ optional: false
50107
+ }],
49932
50108
  "consumables.reset": [{
49933
50109
  name: "deviceId",
49934
50110
  form: "single",
49935
50111
  optional: false
49936
50112
  }],
50113
+ "contact.getStatus": [{
50114
+ name: "deviceId",
50115
+ form: "single",
50116
+ optional: false
50117
+ }],
50118
+ "control.getStatus": [{
50119
+ name: "deviceId",
50120
+ form: "single",
50121
+ optional: false
50122
+ }],
49937
50123
  "control.setValue": [{
49938
50124
  name: "deviceId",
49939
50125
  form: "single",
@@ -49944,6 +50130,11 @@ Object.freeze({
49944
50130
  form: "single",
49945
50131
  optional: false
49946
50132
  }],
50133
+ "cover.getStatus": [{
50134
+ name: "deviceId",
50135
+ form: "single",
50136
+ optional: false
50137
+ }],
49947
50138
  "cover.open": [{
49948
50139
  name: "deviceId",
49949
50140
  form: "single",
@@ -49969,6 +50160,11 @@ Object.freeze({
49969
50160
  form: "single",
49970
50161
  optional: false
49971
50162
  }],
50163
+ "dayNight.getStatus": [{
50164
+ name: "deviceId",
50165
+ form: "single",
50166
+ optional: false
50167
+ }],
49972
50168
  "dayNight.setSettings": [{
49973
50169
  name: "deviceId",
49974
50170
  form: "single",
@@ -49979,11 +50175,31 @@ Object.freeze({
49979
50175
  form: "single",
49980
50176
  optional: true
49981
50177
  }],
50178
+ "detectionPipeline.applyDeviceSettingsPatch": [{
50179
+ name: "deviceId",
50180
+ form: "single",
50181
+ optional: false
50182
+ }],
50183
+ "detectionPipeline.getDeviceLiveContribution": [{
50184
+ name: "deviceId",
50185
+ form: "single",
50186
+ optional: false
50187
+ }],
50188
+ "detectionPipeline.getDeviceSettingsContribution": [{
50189
+ name: "deviceId",
50190
+ form: "single",
50191
+ optional: false
50192
+ }],
49982
50193
  "deviceAdminLink.getAdminLink": [{
49983
50194
  name: "deviceId",
49984
50195
  form: "single",
49985
50196
  optional: false
49986
50197
  }],
50198
+ "deviceAdoption.getStatus": [{
50199
+ name: "deviceId",
50200
+ form: "single",
50201
+ optional: false
50202
+ }],
49987
50203
  "deviceAdoption.release": [{
49988
50204
  name: "camDeviceId",
49989
50205
  form: "single",
@@ -49999,6 +50215,11 @@ Object.freeze({
49999
50215
  form: "single",
50000
50216
  optional: false
50001
50217
  }],
50218
+ "deviceDiscovery.getStatus": [{
50219
+ name: "deviceId",
50220
+ form: "single",
50221
+ optional: false
50222
+ }],
50002
50223
  "deviceDiscovery.listDiscovered": [{
50003
50224
  name: "deviceId",
50004
50225
  form: "single",
@@ -50018,6 +50239,21 @@ Object.freeze({
50018
50239
  form: "single",
50019
50240
  optional: false
50020
50241
  }],
50242
+ "deviceExport.applyDeviceSettingsPatch": [{
50243
+ name: "deviceId",
50244
+ form: "single",
50245
+ optional: false
50246
+ }],
50247
+ "deviceExport.getDeviceLiveContribution": [{
50248
+ name: "deviceId",
50249
+ form: "single",
50250
+ optional: false
50251
+ }],
50252
+ "deviceExport.getDeviceSettingsContribution": [{
50253
+ name: "deviceId",
50254
+ form: "single",
50255
+ optional: false
50256
+ }],
50021
50257
  "deviceExtension.listCandidates": [{
50022
50258
  name: "deviceId",
50023
50259
  form: "single",
@@ -50366,6 +50602,26 @@ Object.freeze({
50366
50602
  form: "single",
50367
50603
  optional: false
50368
50604
  }],
50605
+ "deviceStatus.getStatus": [{
50606
+ name: "deviceId",
50607
+ form: "single",
50608
+ optional: false
50609
+ }],
50610
+ "doorbell.getStatus": [{
50611
+ name: "deviceId",
50612
+ form: "single",
50613
+ optional: false
50614
+ }],
50615
+ "enumSensor.getStatus": [{
50616
+ name: "deviceId",
50617
+ form: "single",
50618
+ optional: false
50619
+ }],
50620
+ "eventEmitter.getStatus": [{
50621
+ name: "deviceId",
50622
+ form: "single",
50623
+ optional: false
50624
+ }],
50369
50625
  "faceGallery.getFaceByTrack": [{
50370
50626
  name: "deviceId",
50371
50627
  form: "single",
@@ -50380,6 +50636,11 @@ Object.freeze({
50380
50636
  form: "array",
50381
50637
  optional: true
50382
50638
  }],
50639
+ "fanControl.getStatus": [{
50640
+ name: "deviceId",
50641
+ form: "single",
50642
+ optional: false
50643
+ }],
50383
50644
  "fanControl.setDirection": [{
50384
50645
  name: "deviceId",
50385
50646
  form: "single",
@@ -50400,6 +50661,26 @@ Object.freeze({
50400
50661
  form: "single",
50401
50662
  optional: false
50402
50663
  }],
50664
+ "featureProbe.getStatus": [{
50665
+ name: "deviceId",
50666
+ form: "single",
50667
+ optional: false
50668
+ }],
50669
+ "flood.getStatus": [{
50670
+ name: "deviceId",
50671
+ form: "single",
50672
+ optional: false
50673
+ }],
50674
+ "gas.getStatus": [{
50675
+ name: "deviceId",
50676
+ form: "single",
50677
+ optional: false
50678
+ }],
50679
+ "humidifier.getStatus": [{
50680
+ name: "deviceId",
50681
+ form: "single",
50682
+ optional: false
50683
+ }],
50403
50684
  "humidifier.setMode": [{
50404
50685
  name: "deviceId",
50405
50686
  form: "single",
@@ -50415,11 +50696,26 @@ Object.freeze({
50415
50696
  form: "single",
50416
50697
  optional: false
50417
50698
  }],
50699
+ "humiditySensor.getStatus": [{
50700
+ name: "deviceId",
50701
+ form: "single",
50702
+ optional: false
50703
+ }],
50704
+ "image.getStatus": [{
50705
+ name: "deviceId",
50706
+ form: "single",
50707
+ optional: false
50708
+ }],
50418
50709
  "imageSettings.getOptions": [{
50419
50710
  name: "deviceId",
50420
50711
  form: "single",
50421
50712
  optional: false
50422
50713
  }],
50714
+ "imageSettings.getStatus": [{
50715
+ name: "deviceId",
50716
+ form: "single",
50717
+ optional: false
50718
+ }],
50423
50719
  "imageSettings.setSettings": [{
50424
50720
  name: "deviceId",
50425
50721
  form: "single",
@@ -50430,6 +50726,11 @@ Object.freeze({
50430
50726
  form: "single",
50431
50727
  optional: false
50432
50728
  }],
50729
+ "intercom.getStatus": [{
50730
+ name: "deviceId",
50731
+ form: "single",
50732
+ optional: false
50733
+ }],
50433
50734
  "intercom.handleAnswer": [{
50434
50735
  name: "deviceId",
50435
50736
  form: "single",
@@ -50460,6 +50761,11 @@ Object.freeze({
50460
50761
  form: "single",
50461
50762
  optional: false
50462
50763
  }],
50764
+ "lawnMowerControl.getStatus": [{
50765
+ name: "deviceId",
50766
+ form: "single",
50767
+ optional: false
50768
+ }],
50463
50769
  "lawnMowerControl.pause": [{
50464
50770
  name: "deviceId",
50465
50771
  form: "single",
@@ -50470,6 +50776,11 @@ Object.freeze({
50470
50776
  form: "single",
50471
50777
  optional: false
50472
50778
  }],
50779
+ "lockControl.getStatus": [{
50780
+ name: "deviceId",
50781
+ form: "single",
50782
+ optional: false
50783
+ }],
50473
50784
  "lockControl.lock": [{
50474
50785
  name: "deviceId",
50475
50786
  form: "single",
@@ -50485,6 +50796,11 @@ Object.freeze({
50485
50796
  form: "single",
50486
50797
  optional: false
50487
50798
  }],
50799
+ "mediaPlayer.getStatus": [{
50800
+ name: "deviceId",
50801
+ form: "single",
50802
+ optional: false
50803
+ }],
50488
50804
  "mediaPlayer.next": [{
50489
50805
  name: "deviceId",
50490
50806
  form: "single",
@@ -50545,6 +50861,11 @@ Object.freeze({
50545
50861
  form: "single",
50546
50862
  optional: false
50547
50863
  }],
50864
+ "motion.getStatus": [{
50865
+ name: "deviceId",
50866
+ form: "single",
50867
+ optional: false
50868
+ }],
50548
50869
  "motion.isDetected": [{
50549
50870
  name: "deviceId",
50550
50871
  form: "single",
@@ -50555,11 +50876,31 @@ Object.freeze({
50555
50876
  form: "single",
50556
50877
  optional: false
50557
50878
  }],
50879
+ "motionDetection.applyDeviceSettingsPatch": [{
50880
+ name: "deviceId",
50881
+ form: "single",
50882
+ optional: false
50883
+ }],
50884
+ "motionDetection.getDeviceLiveContribution": [{
50885
+ name: "deviceId",
50886
+ form: "single",
50887
+ optional: false
50888
+ }],
50889
+ "motionDetection.getDeviceSettingsContribution": [{
50890
+ name: "deviceId",
50891
+ form: "single",
50892
+ optional: false
50893
+ }],
50558
50894
  "motionDetection.removeCamera": [{
50559
50895
  name: "deviceId",
50560
50896
  form: "single",
50561
50897
  optional: false
50562
50898
  }],
50899
+ "motionTrigger.getStatus": [{
50900
+ name: "deviceId",
50901
+ form: "single",
50902
+ optional: false
50903
+ }],
50563
50904
  "motionTrigger.setMotionTrigger": [{
50564
50905
  name: "deviceId",
50565
50906
  form: "single",
@@ -50570,6 +50911,11 @@ Object.freeze({
50570
50911
  form: "single",
50571
50912
  optional: false
50572
50913
  }],
50914
+ "motionZones.getStatus": [{
50915
+ name: "deviceId",
50916
+ form: "single",
50917
+ optional: false
50918
+ }],
50573
50919
  "motionZones.setZone": [{
50574
50920
  name: "deviceId",
50575
50921
  form: "single",
@@ -50580,6 +50926,11 @@ Object.freeze({
50580
50926
  form: "single",
50581
50927
  optional: false
50582
50928
  }],
50929
+ "nativeObjectDetection.getStatus": [{
50930
+ name: "deviceId",
50931
+ form: "single",
50932
+ optional: false
50933
+ }],
50583
50934
  "nativeObjectDetection.setEnabled": [{
50584
50935
  name: "deviceId",
50585
50936
  form: "single",
@@ -50595,6 +50946,11 @@ Object.freeze({
50595
50946
  form: "single",
50596
50947
  optional: false
50597
50948
  }],
50949
+ "navigation.getStatus": [{
50950
+ name: "deviceId",
50951
+ form: "single",
50952
+ optional: false
50953
+ }],
50598
50954
  "navigation.goToPoint": [{
50599
50955
  name: "deviceId",
50600
50956
  form: "single",
@@ -50640,6 +50996,11 @@ Object.freeze({
50640
50996
  form: "single",
50641
50997
  optional: false
50642
50998
  }],
50999
+ "networkLink.getStatus": [{
51000
+ name: "deviceId",
51001
+ form: "single",
51002
+ optional: false
51003
+ }],
50643
51004
  "networkQuality.getDeviceStats": [{
50644
51005
  name: "deviceId",
50645
51006
  form: "single",
@@ -50650,6 +51011,11 @@ Object.freeze({
50650
51011
  form: "single",
50651
51012
  optional: false
50652
51013
  }],
51014
+ "notificationRules.getAlarmSensors": [{
51015
+ name: "deviceIds",
51016
+ form: "array",
51017
+ optional: false
51018
+ }],
50653
51019
  "notificationRules.setDeviceMuted": [{
50654
51020
  name: "deviceId",
50655
51021
  form: "single",
@@ -50660,11 +51026,26 @@ Object.freeze({
50660
51026
  form: "single",
50661
51027
  optional: false
50662
51028
  }],
51029
+ "notifier.getStatus": [{
51030
+ name: "deviceId",
51031
+ form: "single",
51032
+ optional: false
51033
+ }],
50663
51034
  "notifier.send": [{
50664
51035
  name: "deviceId",
50665
51036
  form: "single",
50666
51037
  optional: false
50667
51038
  }],
51039
+ "numericSensor.getStatus": [{
51040
+ name: "deviceId",
51041
+ form: "single",
51042
+ optional: false
51043
+ }],
51044
+ "osd.getStatus": [{
51045
+ name: "deviceId",
51046
+ form: "single",
51047
+ optional: false
51048
+ }],
50668
51049
  "osd.setOverlay": [{
50669
51050
  name: "deviceId",
50670
51051
  form: "single",
@@ -50724,6 +51105,11 @@ Object.freeze({
50724
51105
  form: "single",
50725
51106
  optional: false
50726
51107
  }],
51108
+ "petFeeder.getStatus": [{
51109
+ name: "deviceId",
51110
+ form: "single",
51111
+ optional: false
51112
+ }],
50727
51113
  "petFeeder.markFoodReplenished": [{
50728
51114
  name: "deviceId",
50729
51115
  form: "single",
@@ -50759,6 +51145,11 @@ Object.freeze({
50759
51145
  form: "single",
50760
51146
  optional: false
50761
51147
  }],
51148
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
51149
+ name: "deviceId",
51150
+ form: "single",
51151
+ optional: false
51152
+ }],
50762
51153
  "pipelineAnalytics.clearTrackRelation": [{
50763
51154
  name: "deviceId",
50764
51155
  form: "single",
@@ -50799,6 +51190,16 @@ Object.freeze({
50799
51190
  form: "single",
50800
51191
  optional: false
50801
51192
  }],
51193
+ "pipelineAnalytics.getDeviceLiveContribution": [{
51194
+ name: "deviceId",
51195
+ form: "single",
51196
+ optional: false
51197
+ }],
51198
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
51199
+ name: "deviceId",
51200
+ form: "single",
51201
+ optional: false
51202
+ }],
50802
51203
  "pipelineAnalytics.getEventDensity": [{
50803
51204
  name: "deviceId",
50804
51205
  form: "single",
@@ -51014,6 +51415,11 @@ Object.freeze({
51014
51415
  form: "single",
51015
51416
  optional: true
51016
51417
  }],
51418
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
51419
+ name: "deviceId",
51420
+ form: "single",
51421
+ optional: false
51422
+ }],
51017
51423
  "pipelineOrchestrator.assignAudio": [{
51018
51424
  name: "deviceId",
51019
51425
  form: "single",
@@ -51059,6 +51465,16 @@ Object.freeze({
51059
51465
  form: "single",
51060
51466
  optional: false
51061
51467
  }],
51468
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
51469
+ name: "deviceId",
51470
+ form: "single",
51471
+ optional: false
51472
+ }],
51473
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
51474
+ name: "deviceId",
51475
+ form: "single",
51476
+ optional: false
51477
+ }],
51062
51478
  "pipelineOrchestrator.getPipelineAssignment": [{
51063
51479
  name: "deviceId",
51064
51480
  form: "single",
@@ -51179,11 +51595,31 @@ Object.freeze({
51179
51595
  form: "single",
51180
51596
  optional: true
51181
51597
  }],
51598
+ "powerMeter.getStatus": [{
51599
+ name: "deviceId",
51600
+ form: "single",
51601
+ optional: false
51602
+ }],
51603
+ "presence.getStatus": [{
51604
+ name: "deviceId",
51605
+ form: "single",
51606
+ optional: false
51607
+ }],
51608
+ "pressureSensor.getStatus": [{
51609
+ name: "deviceId",
51610
+ form: "single",
51611
+ optional: false
51612
+ }],
51182
51613
  "privacyMask.getOptions": [{
51183
51614
  name: "deviceId",
51184
51615
  form: "single",
51185
51616
  optional: false
51186
51617
  }],
51618
+ "privacyMask.getStatus": [{
51619
+ name: "deviceId",
51620
+ form: "single",
51621
+ optional: false
51622
+ }],
51187
51623
  "privacyMask.setAudioEnabled": [{
51188
51624
  name: "deviceId",
51189
51625
  form: "single",
@@ -51234,6 +51670,11 @@ Object.freeze({
51234
51670
  form: "single",
51235
51671
  optional: false
51236
51672
  }],
51673
+ "ptz.getStatus": [{
51674
+ name: "deviceId",
51675
+ form: "single",
51676
+ optional: false
51677
+ }],
51237
51678
  "ptz.goHome": [{
51238
51679
  name: "deviceId",
51239
51680
  form: "single",
@@ -51324,6 +51765,11 @@ Object.freeze({
51324
51765
  form: "single",
51325
51766
  optional: false
51326
51767
  }],
51768
+ "recordingArchive.applyDeviceSettingsPatch": [{
51769
+ name: "deviceId",
51770
+ form: "single",
51771
+ optional: false
51772
+ }],
51327
51773
  "recordingArchive.deleteFootprint": [{
51328
51774
  name: "deviceId",
51329
51775
  form: "single",
@@ -51344,6 +51790,21 @@ Object.freeze({
51344
51790
  form: "single",
51345
51791
  optional: false
51346
51792
  }],
51793
+ "recordingArchive.getDeviceLiveContribution": [{
51794
+ name: "deviceId",
51795
+ form: "single",
51796
+ optional: false
51797
+ }],
51798
+ "recordingArchive.getDeviceSettingsContribution": [{
51799
+ name: "deviceId",
51800
+ form: "single",
51801
+ optional: false
51802
+ }],
51803
+ "recordingArchive.getStatus": [{
51804
+ name: "deviceId",
51805
+ form: "single",
51806
+ optional: false
51807
+ }],
51347
51808
  "recordingArchive.listOpsLog": [{
51348
51809
  name: "deviceId",
51349
51810
  form: "single",
@@ -51429,6 +51890,11 @@ Object.freeze({
51429
51890
  form: "single",
51430
51891
  optional: false
51431
51892
  }],
51893
+ "recordingOnboard.getStatus": [{
51894
+ name: "deviceId",
51895
+ form: "single",
51896
+ optional: false
51897
+ }],
51432
51898
  "recordingOnboard.setSettings": [{
51433
51899
  name: "deviceId",
51434
51900
  form: "single",
@@ -51459,6 +51925,11 @@ Object.freeze({
51459
51925
  form: "single",
51460
51926
  optional: false
51461
51927
  }],
51928
+ "sceneMonitor.getStatus": [{
51929
+ name: "deviceId",
51930
+ form: "single",
51931
+ optional: false
51932
+ }],
51462
51933
  "sceneMonitor.listScenes": [{
51463
51934
  name: "deviceId",
51464
51935
  form: "single",
@@ -51484,6 +51955,11 @@ Object.freeze({
51484
51955
  form: "single",
51485
51956
  optional: false
51486
51957
  }],
51958
+ "scriptRunner.getStatus": [{
51959
+ name: "deviceId",
51960
+ form: "single",
51961
+ optional: false
51962
+ }],
51487
51963
  "scriptRunner.run": [{
51488
51964
  name: "deviceId",
51489
51965
  form: "single",
@@ -51494,11 +51970,31 @@ Object.freeze({
51494
51970
  form: "single",
51495
51971
  optional: false
51496
51972
  }],
51973
+ "smoke.getStatus": [{
51974
+ name: "deviceId",
51975
+ form: "single",
51976
+ optional: false
51977
+ }],
51978
+ "snapshot.applyDeviceSettingsPatch": [{
51979
+ name: "deviceId",
51980
+ form: "single",
51981
+ optional: false
51982
+ }],
51497
51983
  "snapshot.getDebugState": [{
51498
51984
  name: "deviceId",
51499
51985
  form: "single",
51500
51986
  optional: false
51501
51987
  }],
51988
+ "snapshot.getDeviceLiveContribution": [{
51989
+ name: "deviceId",
51990
+ form: "single",
51991
+ optional: false
51992
+ }],
51993
+ "snapshot.getDeviceSettingsContribution": [{
51994
+ name: "deviceId",
51995
+ form: "single",
51996
+ optional: false
51997
+ }],
51502
51998
  "snapshot.getSnapshot": [{
51503
51999
  name: "deviceId",
51504
52000
  form: "single",
@@ -51515,6 +52011,11 @@ Object.freeze({
51515
52011
  form: "array",
51516
52012
  optional: false
51517
52013
  }],
52014
+ "snapshot.getStatus": [{
52015
+ name: "deviceId",
52016
+ form: "single",
52017
+ optional: false
52018
+ }],
51518
52019
  "snapshot.invalidateCache": [{
51519
52020
  name: "deviceId",
51520
52021
  form: "single",
@@ -51525,6 +52026,11 @@ Object.freeze({
51525
52026
  form: "single",
51526
52027
  optional: false
51527
52028
  }],
52029
+ "streamBroker.applyDeviceSettingsPatch": [{
52030
+ name: "deviceId",
52031
+ form: "single",
52032
+ optional: false
52033
+ }],
51528
52034
  "streamBroker.assignProfile": [{
51529
52035
  name: "deviceId",
51530
52036
  form: "single",
@@ -51540,6 +52046,16 @@ Object.freeze({
51540
52046
  form: "single",
51541
52047
  optional: false
51542
52048
  }],
52049
+ "streamBroker.getDeviceLiveContribution": [{
52050
+ name: "deviceId",
52051
+ form: "single",
52052
+ optional: false
52053
+ }],
52054
+ "streamBroker.getDeviceSettingsContribution": [{
52055
+ name: "deviceId",
52056
+ form: "single",
52057
+ optional: false
52058
+ }],
51543
52059
  "streamBroker.getStreamWithCodec": [{
51544
52060
  name: "deviceId",
51545
52061
  form: "single",
@@ -51600,16 +52116,46 @@ Object.freeze({
51600
52116
  form: "single",
51601
52117
  optional: false
51602
52118
  }],
52119
+ "streamParams.getStatus": [{
52120
+ name: "deviceId",
52121
+ form: "single",
52122
+ optional: false
52123
+ }],
51603
52124
  "streamParams.setProfile": [{
51604
52125
  name: "deviceId",
51605
52126
  form: "single",
51606
52127
  optional: false
51607
52128
  }],
52129
+ "switch.getStatus": [{
52130
+ name: "deviceId",
52131
+ form: "single",
52132
+ optional: false
52133
+ }],
51608
52134
  "switch.setState": [{
51609
52135
  name: "deviceId",
51610
52136
  form: "single",
51611
52137
  optional: false
51612
52138
  }],
52139
+ "tamper.getStatus": [{
52140
+ name: "deviceId",
52141
+ form: "single",
52142
+ optional: false
52143
+ }],
52144
+ "temperatureSensor.getStatus": [{
52145
+ name: "deviceId",
52146
+ form: "single",
52147
+ optional: false
52148
+ }],
52149
+ "update.getStatus": [{
52150
+ name: "deviceId",
52151
+ form: "single",
52152
+ optional: false
52153
+ }],
52154
+ "vacuumControl.getStatus": [{
52155
+ name: "deviceId",
52156
+ form: "single",
52157
+ optional: false
52158
+ }],
51613
52159
  "vacuumControl.locate": [{
51614
52160
  name: "deviceId",
51615
52161
  form: "single",
@@ -51645,6 +52191,11 @@ Object.freeze({
51645
52191
  form: "single",
51646
52192
  optional: false
51647
52193
  }],
52194
+ "valve.getStatus": [{
52195
+ name: "deviceId",
52196
+ form: "single",
52197
+ optional: false
52198
+ }],
51648
52199
  "valve.open": [{
51649
52200
  name: "deviceId",
51650
52201
  form: "single",
@@ -51660,6 +52211,11 @@ Object.freeze({
51660
52211
  form: "single",
51661
52212
  optional: false
51662
52213
  }],
52214
+ "vibration.getStatus": [{
52215
+ name: "deviceId",
52216
+ form: "single",
52217
+ optional: false
52218
+ }],
51663
52219
  "videoclips.dialClipStream": [{
51664
52220
  name: "deviceId",
51665
52221
  form: "single",
@@ -51695,6 +52251,11 @@ Object.freeze({
51695
52251
  form: "single",
51696
52252
  optional: false
51697
52253
  }],
52254
+ "waterHeater.getStatus": [{
52255
+ name: "deviceId",
52256
+ form: "single",
52257
+ optional: false
52258
+ }],
51698
52259
  "waterHeater.setAway": [{
51699
52260
  name: "deviceId",
51700
52261
  form: "single",
@@ -51710,6 +52271,11 @@ Object.freeze({
51710
52271
  form: "single",
51711
52272
  optional: false
51712
52273
  }],
52274
+ "weather.getStatus": [{
52275
+ name: "deviceId",
52276
+ form: "single",
52277
+ optional: false
52278
+ }],
51713
52279
  "webrtcSession.addIceCandidate": [{
51714
52280
  name: "deviceId",
51715
52281
  form: "single",
@@ -52447,7 +53013,7 @@ var PreviewTextField = string().max(200);
52447
53013
  * Whether the notification's preview is a STILL or a short animation.
52448
53014
  *
52449
53015
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
52450
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
53016
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
52451
53017
  * night reads better as three seconds of motion than as one frame of it. Both
52452
53018
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
52453
53019
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -52585,6 +53151,7 @@ TimelapseRuleInputSchema.extend({
52585
53151
  createdAt: number(),
52586
53152
  updatedAt: number()
52587
53153
  });
53154
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
52588
53155
  object({
52589
53156
  /**
52590
53157
  * Fraction of the box's own size added on EACH side before cutting.