@camstack/addon-post-analysis 1.2.666 → 1.2.667

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 (16) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{clip-model-registry-BIhYJRFt.js → clip-model-registry-D7cqhFK3.js} +731 -485
  3. package/dist/{clip-model-registry-Uc_C1x81.mjs → clip-model-registry-DpzRS8q3.mjs} +731 -485
  4. package/dist/embedding-encoder/index.js +1 -1
  5. package/dist/embedding-encoder/index.mjs +1 -1
  6. package/dist/pipeline-analytics/_stub.js +2 -2
  7. package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-FkeZoNXj.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DmTIEp0m.mjs} +2 -2
  8. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DAAkZRnK.mjs +26 -0
  9. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-znrgUrN1.mjs +26 -0
  10. package/dist/pipeline-analytics/{hostInit-BBhgVoNl.mjs → hostInit-ODebWXu_.mjs} +2 -2
  11. package/dist/pipeline-analytics/index.js +449 -114
  12. package/dist/pipeline-analytics/index.mjs +449 -114
  13. package/dist/pipeline-analytics/remoteEntry.js +1 -1
  14. package/package.json +2 -2
  15. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CnYZAdvw.mjs +0 -26
  16. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Br6eWzp_.mjs +0 -26
@@ -816,7 +816,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
816
816
  return EventCategory;
817
817
  }({});
818
818
  //#endregion
819
- //#region ../types/dist/device-type-CfHw_quR.mjs
819
+ //#region ../types/dist/device-type-D1fH5kaC.mjs
820
820
  /**
821
821
  import { errMsg } from '@camstack/types'
822
822
  * Extract a human-readable message from an unknown error value.
@@ -1047,6 +1047,12 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
1047
1047
  DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
1048
1048
  /** Media player exposes stop distinct from pause. */
1049
1049
  DeviceFeature["MediaPlayerStop"] = "media-player-stop";
1050
+ /** Media player exposes volume up / down in steps (an infrared TV has no level). */
1051
+ DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
1052
+ /** Media player exposes channel up / down in steps. */
1053
+ DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
1054
+ /** Media player exposes power on / off. */
1055
+ DeviceFeature["MediaPlayerPower"] = "media-player-power";
1050
1056
  /** Alarm panel requires a PIN code on arm/disarm. */
1051
1057
  DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
1052
1058
  /** Presence device carries GPS coordinates (lat/lng/accuracy) in
@@ -6063,7 +6069,7 @@ var ZodIssueCode = {
6063
6069
  var ZodFirstPartyTypeKind;
6064
6070
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6065
6071
  //#endregion
6066
- //#region ../types/dist/sleep-C6LqREpb.mjs
6072
+ //#region ../types/dist/sleep-hK-Dss3z.mjs
6067
6073
  /**
6068
6074
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6069
6075
  * window to float samples (D455).
@@ -8151,6 +8157,10 @@ var BaseAddon = class {
8151
8157
  const stored = keychain ? await this.readAddonStoreWithRetry() : {};
8152
8158
  const patch = {};
8153
8159
  for (const key of keys) {
8160
+ if (tree.get(key)?.kind === "array") {
8161
+ patch[key] = [];
8162
+ continue;
8163
+ }
8154
8164
  const keychainStored = tree.has(key) || collectSecretMarkerRefs(stored[key]).length > 0;
8155
8165
  patch[key] = keychain && keychainStored ? SECRET_CLEAR : "";
8156
8166
  }
@@ -11999,7 +12009,7 @@ function sleep(ms) {
11999
12009
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
12000
12010
  }
12001
12011
  //#endregion
12002
- //#region ../types/dist/composition-Dh3RfMx5.mjs
12012
+ //#region ../types/dist/composition-BSGHhcr8.mjs
12003
12013
  /**
12004
12014
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
12005
12015
  * canonical form sorts object keys alphabetically at every depth so two
@@ -12922,38 +12932,6 @@ function validateExpressionSource(src) {
12922
12932
  return null;
12923
12933
  }
12924
12934
  /**
12925
- * One power reading becomes a washer, dryer or dishwasher (D944 helper).
12926
- *
12927
- * Standby of the control board is under 5 W; a motor or a heater is far
12928
- * above that, so 5 W is the line. A door lock or a short pump spike is not
12929
- * a cycle, so running starts only after 30 s above the line.
12930
- *
12931
- * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
12932
- * bursts) lasts several minutes. Ending the cycle on the first dip would
12933
- * report "finished" in the middle of the program, so the stop dwell is
12934
- * 10 minutes on every type. The number is stored per type so one machine
12935
- * can move later without moving the others.
12936
- */
12937
- var APPLIANCE_TEMPLATE_ID = "appliance";
12938
- var APPLIANCE_KINDS = [
12939
- "washer",
12940
- "dryer",
12941
- "dishwasher"
12942
- ];
12943
- DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
12944
- /**
12945
- * A dumb plug-in stove or heater, built from a smart plug (a `Heater`).
12946
- *
12947
- * The plug is the actuator: `switch.setState` is a FORWARD to the plug's own
12948
- * (D967), so the heater switches exactly as the plug does. Running is the
12949
- * plug being on; when a power reading is also named, running is the draw
12950
- * staying above the line instead (a plug left on with the stove's own
12951
- * thermostat open is not heating). 50 W is far above any standby and below
12952
- * the smallest radiator.
12953
- */
12954
- var HEATER_TEMPLATE_ID = "heater";
12955
- DeviceType.Heater;
12956
- /**
12957
12935
  * Statistics and integrals over a history read (D944).
12958
12936
  *
12959
12937
  * Pure: the same points always give the same answer, so a restart recomputes
@@ -13097,34 +13075,6 @@ var HelperSpecSchema = discriminatedUnion("kind", [
13097
13075
  /** Actuator groups only. Readings leave this unset. */
13098
13076
  active: ActiveCriterionSchema.optional()
13099
13077
  }),
13100
- object({
13101
- kind: literal("appliance"),
13102
- templateId: literal(APPLIANCE_TEMPLATE_ID),
13103
- appliance: _enum(APPLIANCE_KINDS),
13104
- thresholdWatts: number().positive(),
13105
- startDwellMs: number().int().nonnegative(),
13106
- stopDwellMs: number().int().nonnegative(),
13107
- member: HelperMemberSchema,
13108
- /**
13109
- * The plug that powers the appliance (`switch.on`). Optional: when set, the
13110
- * composition carries a `power-source` feature, so the hub can cut and restore
13111
- * that plug (power-source link of a NEW-target composition).
13112
- */
13113
- powerSwitch: HelperMemberSchema.optional(),
13114
- /** How long a forced restart keeps the plug off; the cap's default when unset. */
13115
- offSeconds: number().optional()
13116
- }),
13117
- object({
13118
- kind: literal("heater"),
13119
- templateId: literal(HEATER_TEMPLATE_ID),
13120
- /** The plug, read and commanded at `switch.on`. */
13121
- plug: HelperMemberSchema,
13122
- /** The plug's power reading, when it has one: running is then the draw, not the switch. */
13123
- meter: HelperMemberSchema.optional(),
13124
- thresholdWatts: number().positive(),
13125
- startDwellMs: number().int().nonnegative(),
13126
- stopDwellMs: number().int().nonnegative()
13127
- }),
13128
13078
  object({
13129
13079
  kind: literal("statistic"),
13130
13080
  stat: _enum(STATISTIC_STATS),
@@ -13296,7 +13246,14 @@ var CompositionForwardCommandSchema = object({
13296
13246
  method: string().min(1),
13297
13247
  args: record(string().min(1), CompositionForwardArgSchema).optional()
13298
13248
  });
13299
- var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
13249
+ var CompositionCommandTargetSchema = discriminatedUnion("kind", [
13250
+ CompositionForwardCommandSchema,
13251
+ CompositionCodeSourceSchema,
13252
+ object({
13253
+ kind: literal("extension"),
13254
+ target: literal("remote")
13255
+ })
13256
+ ]);
13300
13257
  /** An item key inside an item-array cap (`consumables.items[<key>]`). */
13301
13258
  var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
13302
13259
  /**
@@ -13341,7 +13298,7 @@ var CompositionSchema = object({
13341
13298
  kind: literal("existing"),
13342
13299
  device: CompositionSourceRefSchema
13343
13300
  })]),
13344
- features: array(CompositionFeatureSchema).min(1).max(16),
13301
+ features: array(CompositionFeatureSchema).min(0).max(16),
13345
13302
  /**
13346
13303
  * Present when the block is a helper template. Absent on a free
13347
13304
  * composition (the room example, device 4603). The editor reads this,
@@ -20563,6 +20520,48 @@ var APPLIANCE_CAP_VOCABULARY = {
20563
20520
  scope: "device",
20564
20521
  noun: t("Media player", "Lettore multimediale"),
20565
20522
  actions: [
20523
+ {
20524
+ id: "media.turnOn",
20525
+ method: "turnOn",
20526
+ label: t("Turn on", "Accendi"),
20527
+ phrase: t("Turn on {device}", "Accendi {device}"),
20528
+ icon: "power"
20529
+ },
20530
+ {
20531
+ id: "media.turnOff",
20532
+ method: "turnOff",
20533
+ label: t("Turn off", "Spegni"),
20534
+ phrase: t("Turn off {device}", "Spegni {device}"),
20535
+ icon: "power"
20536
+ },
20537
+ {
20538
+ id: "media.volumeUp",
20539
+ method: "volumeUp",
20540
+ label: t("Volume up", "Alza il volume"),
20541
+ phrase: t("Raise the volume of {device}", "Alza il volume di {device}"),
20542
+ icon: "volume-2"
20543
+ },
20544
+ {
20545
+ id: "media.volumeDown",
20546
+ method: "volumeDown",
20547
+ label: t("Volume down", "Abbassa il volume"),
20548
+ phrase: t("Lower the volume of {device}", "Abbassa il volume di {device}"),
20549
+ icon: "volume-2"
20550
+ },
20551
+ {
20552
+ id: "media.channelUp",
20553
+ method: "channelUp",
20554
+ label: t("Channel up", "Canale successivo"),
20555
+ phrase: t("Go to the next channel on {device}", "Passa al canale successivo su {device}"),
20556
+ icon: "skip-forward"
20557
+ },
20558
+ {
20559
+ id: "media.channelDown",
20560
+ method: "channelDown",
20561
+ label: t("Channel down", "Canale precedente"),
20562
+ phrase: t("Go to the previous channel on {device}", "Torna al canale precedente su {device}"),
20563
+ icon: "skip-back"
20564
+ },
20566
20565
  {
20567
20566
  id: "media.play",
20568
20567
  method: "play",
@@ -50365,6 +50364,244 @@ var controlCapability = {
50365
50364
  */
50366
50365
  history: "none"
50367
50366
  };
50367
+ /**
50368
+ * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
50369
+ * Apple TV, Spotify, Roku, generic OTT receivers, …) on
50370
+ * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
50371
+ * surface — those use `DeviceType.Camera` + the broker pipeline.
50372
+ *
50373
+ * The cap declares a wide method surface; not every backend supports
50374
+ * every method. Drivers signal sub-capability via the
50375
+ * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
50376
+ * corresponding method) so the UI gates buttons without a slice
50377
+ * fetch — same pattern as `PanTiltZoom` for cameras.
50378
+ */
50379
+ var MediaPlayerStateSchema = _enum([
50380
+ "off",
50381
+ "on",
50382
+ "idle",
50383
+ "playing",
50384
+ "paused",
50385
+ "buffering",
50386
+ "standby"
50387
+ ]);
50388
+ var MediaPlayerRepeatSchema = _enum([
50389
+ "off",
50390
+ "all",
50391
+ "one"
50392
+ ]);
50393
+ var MediaInfoSchema = object({
50394
+ /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
50395
+ * `podcast`, …). */
50396
+ type: string(),
50397
+ /** Human-readable title. */
50398
+ title: string(),
50399
+ /** Optional artist / channel / station label. */
50400
+ artist: string().optional(),
50401
+ /** Optional album / season / show name. */
50402
+ album: string().optional(),
50403
+ /** Optional cover-art / thumbnail URL. */
50404
+ imageUrl: string().optional()
50405
+ });
50406
+ /**
50407
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
50408
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
50409
+ * tracks what it last SENT; it moves only after a send was accepted, and a
50410
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
50411
+ * guess, never as a reading.
50412
+ */
50413
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
50414
+ /** The fields of a media-player status a driver can only guess. */
50415
+ var MediaPlayerAssumedFieldSchema = _enum([
50416
+ "state",
50417
+ "volumeLevel",
50418
+ "isMuted",
50419
+ "source"
50420
+ ]);
50421
+ var MediaPlayerStatusSchema = object({
50422
+ /** Playback lifecycle state. */
50423
+ state: MediaPlayerStateSchema,
50424
+ /**
50425
+ * Whether the state fields are readings or the driver's own bookkeeping.
50426
+ * A slice written before this field existed parses as `reported`.
50427
+ */
50428
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
50429
+ /**
50430
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
50431
+ * this is not empty; a field not listed here is a reading even then (power
50432
+ * from a running-state source, mute guessed from the last send).
50433
+ */
50434
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
50435
+ /** Volume as 0..100 inclusive. Null when the device has no volume
50436
+ * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
50437
+ volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
50438
+ /** Mute toggle distinct from volume=0. Null when no mute surface.
50439
+ * Pair with `DeviceFeature.MediaPlayerMute`. */
50440
+ isMuted: boolean().nullable(),
50441
+ /** Active source / input. Empty when no source surface. */
50442
+ source: string(),
50443
+ /** Selectable sources. Empty when no source surface.
50444
+ * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
50445
+ availableSources: array(string()),
50446
+ /** Currently-playing media info. Null when nothing is playing. */
50447
+ currentMedia: MediaInfoSchema.nullable(),
50448
+ /** Current playback position in ms. Null when not seekable or
50449
+ * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
50450
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
50451
+ /** Total duration of the current media in ms. Null when unknown
50452
+ * (live stream) or nothing is playing. */
50453
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
50454
+ /** Shuffle toggle. Null when no shuffle surface.
50455
+ * Pair with `DeviceFeature.MediaPlayerShuffle`. */
50456
+ shuffle: boolean().nullable(),
50457
+ /** Repeat mode. Null when no repeat surface.
50458
+ * Pair with `DeviceFeature.MediaPlayerRepeat`. */
50459
+ repeat: MediaPlayerRepeatSchema.nullable(),
50460
+ /** Ms epoch when the slice was last updated. */
50461
+ lastChangedAt: number()
50462
+ });
50463
+ var stepInput = object({
50464
+ deviceId: number().int().nonnegative(),
50465
+ /** How many presses: the caller's count (Alexa `volumeSteps`, `channelCount`). */
50466
+ steps: number().int().min(1).max(50).default(1)
50467
+ });
50468
+ var deviceOnly = object({ deviceId: number().int().nonnegative() });
50469
+ var mediaPlayerCapability = {
50470
+ name: "media-player",
50471
+ scope: "device",
50472
+ deviceNative: true,
50473
+ mode: "singleton",
50474
+ deviceTypes: [DeviceType.MediaPlayer],
50475
+ methods: {
50476
+ turnOn: method(deviceOnly, _void(), {
50477
+ kind: "mutation",
50478
+ auth: "protected"
50479
+ }),
50480
+ turnOff: method(deviceOnly, _void(), {
50481
+ kind: "mutation",
50482
+ auth: "protected"
50483
+ }),
50484
+ volumeUp: method(stepInput, _void(), {
50485
+ kind: "mutation",
50486
+ auth: "protected"
50487
+ }),
50488
+ volumeDown: method(stepInput, _void(), {
50489
+ kind: "mutation",
50490
+ auth: "protected"
50491
+ }),
50492
+ channelUp: method(stepInput, _void(), {
50493
+ kind: "mutation",
50494
+ auth: "protected"
50495
+ }),
50496
+ channelDown: method(stepInput, _void(), {
50497
+ kind: "mutation",
50498
+ auth: "protected"
50499
+ }),
50500
+ play: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50501
+ kind: "mutation",
50502
+ auth: "protected"
50503
+ }),
50504
+ pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50505
+ kind: "mutation",
50506
+ auth: "protected"
50507
+ }),
50508
+ stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50509
+ kind: "mutation",
50510
+ auth: "protected"
50511
+ }),
50512
+ next: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50513
+ kind: "mutation",
50514
+ auth: "protected"
50515
+ }),
50516
+ previous: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50517
+ kind: "mutation",
50518
+ auth: "protected"
50519
+ }),
50520
+ seek: method(object({
50521
+ deviceId: number().int().nonnegative(),
50522
+ position: number().int().nonnegative()
50523
+ }), _void(), {
50524
+ kind: "mutation",
50525
+ auth: "protected"
50526
+ }),
50527
+ setVolume: method(object({
50528
+ deviceId: number().int().nonnegative(),
50529
+ volumeLevel: number().min(0).max(100)
50530
+ }), _void(), {
50531
+ kind: "mutation",
50532
+ auth: "protected"
50533
+ }),
50534
+ setMute: method(object({
50535
+ deviceId: number().int().nonnegative(),
50536
+ muted: boolean()
50537
+ }), _void(), {
50538
+ kind: "mutation",
50539
+ auth: "protected"
50540
+ }),
50541
+ setShuffle: method(object({
50542
+ deviceId: number().int().nonnegative(),
50543
+ shuffle: boolean()
50544
+ }), _void(), {
50545
+ kind: "mutation",
50546
+ auth: "protected"
50547
+ }),
50548
+ setRepeat: method(object({
50549
+ deviceId: number().int().nonnegative(),
50550
+ repeat: MediaPlayerRepeatSchema
50551
+ }), _void(), {
50552
+ kind: "mutation",
50553
+ auth: "protected"
50554
+ }),
50555
+ selectSource: method(object({
50556
+ deviceId: number().int().nonnegative(),
50557
+ source: string().min(1)
50558
+ }), _void(), {
50559
+ kind: "mutation",
50560
+ auth: "protected"
50561
+ }),
50562
+ playMedia: method(object({
50563
+ deviceId: number().int().nonnegative(),
50564
+ /** Media identifier / URL. */
50565
+ mediaId: string().min(1),
50566
+ /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
50567
+ * passes it through to the upstream service. */
50568
+ mediaType: string().min(1)
50569
+ }), _void(), {
50570
+ kind: "mutation",
50571
+ auth: "protected"
50572
+ })
50573
+ },
50574
+ status: {
50575
+ schema: MediaPlayerStatusSchema,
50576
+ kind: "push"
50577
+ },
50578
+ /**
50579
+ * Runtime-state slice — mirrored by the kernel. UI players read the
50580
+ * full slice for live now-playing, volume, and progress updates
50581
+ * without polling.
50582
+ */
50583
+ runtimeState: MediaPlayerStatusSchema,
50584
+ /**
50585
+ * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
50586
+ *
50587
+ * See `RuntimeStateDurability`. Enforced by
50588
+ * `scripts/check-runtime-state-durability.ts`.
50589
+ */
50590
+ durability: "session",
50591
+ /**
50592
+ * History (D850): volume (a level an operator or an automation sets; the
50593
+ * default 10 s floor folds a slider drag into its end value) and mute.
50594
+ * `position` is not recorded: it moves continuously while playing.
50595
+ */
50596
+ history: { fields: {
50597
+ volumeLevel: {
50598
+ kind: "gauge",
50599
+ unit: "%",
50600
+ deadband: 1
50601
+ },
50602
+ isMuted: { kind: "boolean" }
50603
+ } }
50604
+ };
50368
50605
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Heater, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Fan, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.PetFountain, DeviceType.Fan, DeviceType.Humidifier, DeviceType.Climate, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder, DeviceType.Heater;
50369
50606
  var NUMBER = {
50370
50607
  kind: "fixed",
@@ -50812,117 +51049,6 @@ function actuator(input) {
50812
51049
  };
50813
51050
  }
50814
51051
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
50815
- var PowerSourceRefusalReasonSchema = _enum([
50816
- "no-power-source",
50817
- "switch-missing",
50818
- "switch-offline",
50819
- "switch-unknown",
50820
- "restart-in-progress",
50821
- "switch-call-failed"
50822
- ]);
50823
- var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
50824
- accepted: literal(false),
50825
- reason: PowerSourceRefusalReasonSchema,
50826
- /** One line for the operator, naming the switch. */
50827
- message: string()
50828
- })]);
50829
- var PowerSourceInfoSchema = object({
50830
- /** False when the device has no power source linked; the rest is then empty. */
50831
- linked: boolean(),
50832
- switchDeviceId: number().nullable(),
50833
- switchName: string().nullable(),
50834
- /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
50835
- switchOn: boolean().nullable(),
50836
- switchOnline: boolean().nullable(),
50837
- restartInProgress: boolean(),
50838
- offSeconds: number().int()
50839
- });
50840
- /** The composed slice: the switch state the link mirrors, plus the stored off time. */
50841
- var PowerSourceStateSchema = object({
50842
- /** Null while the switch has not reported: unknown is never `false` (D393). */
50843
- switchOn: boolean().nullable(),
50844
- offSeconds: number().int(),
50845
- lastFetchedAt: number()
50846
- });
50847
- var POWER_SOURCE_DEVICE_TYPES = [
50848
- DeviceType.Gateway,
50849
- DeviceType.Hub,
50850
- DeviceType.Camera,
50851
- DeviceType.Sensor,
50852
- DeviceType.MediaPlayer,
50853
- DeviceType.Vacuum,
50854
- DeviceType.Generic,
50855
- DeviceType.Washer,
50856
- DeviceType.Dryer,
50857
- DeviceType.Dishwasher,
50858
- DeviceType.PetFountain,
50859
- DeviceType.Fan,
50860
- DeviceType.Humidifier,
50861
- DeviceType.Climate,
50862
- DeviceType.WaterHeater
50863
- ];
50864
- var powerSourceCustomize = {
50865
- version: 1,
50866
- targets: [{
50867
- id: "switch",
50868
- cardinality: "scalar",
50869
- vocabulary: {
50870
- cap: "power-source",
50871
- stateField: "switchOn"
50872
- },
50873
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
50874
- apply: "add",
50875
- path: "switchOn",
50876
- sources: [{
50877
- kind: "switch",
50878
- transforms: [{ kind: "identity" }]
50879
- }],
50880
- companions: [{
50881
- kind: "constant",
50882
- path: "offSeconds",
50883
- value: 10,
50884
- when: "add"
50885
- }, {
50886
- kind: "clock",
50887
- path: "lastFetchedAt",
50888
- when: "always"
50889
- }],
50890
- sourceReport: { status: "assignment-status" }
50891
- }]
50892
- };
50893
- var deviceInput$2 = object({ deviceId: number().int().nonnegative() });
50894
- var powerSourceCapability = {
50895
- name: "power-source",
50896
- scope: "device",
50897
- mode: "singleton",
50898
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
50899
- methods: {
50900
- getStatus: systemMethod(deviceInput$2, PowerSourceInfoSchema, { auth: "admin" }),
50901
- powerOn: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
50902
- kind: "mutation",
50903
- auth: "admin"
50904
- }),
50905
- powerOff: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
50906
- kind: "mutation",
50907
- auth: "admin"
50908
- }),
50909
- forceRestart: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
50910
- kind: "mutation",
50911
- auth: "admin"
50912
- })
50913
- },
50914
- runtimeState: PowerSourceStateSchema,
50915
- customize: powerSourceCustomize,
50916
- /**
50917
- * Runtime-state durability: **session** — mirrored from the linked switch on
50918
- * its next report; a restored value would outlive the reading it names.
50919
- *
50920
- * See `RuntimeStateDurability`. Enforced by
50921
- * `scripts/check-runtime-state-durability.ts`.
50922
- */
50923
- durability: "session",
50924
- history: "none"
50925
- };
50926
51052
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
50927
51053
  DeviceType.Camera;
50928
51054
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
@@ -50950,6 +51076,165 @@ var ComposableCapabilitiesSchema = object({ caps: array(object({
50950
51076
  }).optional()
50951
51077
  })) });
50952
51078
  /**
51079
+ * A saved Customize assignment (D936). The schema is the type: callers use
51080
+ * `z.infer`, they do not restate the shape.
51081
+ */
51082
+ var OverrideSourceSchema = object({
51083
+ addonId: string().min(1),
51084
+ stableId: string().min(1),
51085
+ cap: string().min(1),
51086
+ fieldPath: string().min(1)
51087
+ });
51088
+ var IdentityTransformDraftSchema = object({ kind: literal("identity") });
51089
+ var InvertTransformDraftSchema = object({ kind: literal("invert") });
51090
+ var ThresholdTransformDraftSchema = object({
51091
+ kind: literal("threshold"),
51092
+ comparison: _enum(["gte", "lte"]),
51093
+ threshold: number(),
51094
+ startDwellMs: number().nonnegative(),
51095
+ stopDwellMs: number().nonnegative()
51096
+ });
51097
+ var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
51098
+ IdentityTransformDraftSchema,
51099
+ InvertTransformDraftSchema,
51100
+ ThresholdTransformDraftSchema,
51101
+ object({
51102
+ kind: literal("linear"),
51103
+ scale: number(),
51104
+ offset: number(),
51105
+ clampMin: number().optional(),
51106
+ clampMax: number().optional()
51107
+ }),
51108
+ object({
51109
+ kind: literal("enum-map"),
51110
+ mapping: record(string(), string().nullable())
51111
+ }),
51112
+ object({ kind: literal("number") })
51113
+ ]);
51114
+ var ScalarOverrideDraftSchema = object({
51115
+ kind: literal("scalar"),
51116
+ cap: string().min(1),
51117
+ targetId: string().min(1),
51118
+ source: OverrideSourceSchema,
51119
+ transform: CustomizeTransformDraftSchema
51120
+ });
51121
+ var KeyedArrayOverrideDraftSchema = object({
51122
+ kind: literal("keyedArray"),
51123
+ cap: string().min(1),
51124
+ targetId: string().min(1),
51125
+ key: string().min(1),
51126
+ label: string().min(1),
51127
+ fieldPath: string().min(1),
51128
+ source: OverrideSourceSchema,
51129
+ transform: CustomizeTransformDraftSchema
51130
+ });
51131
+ var PulseOverrideDraftSchema = object({
51132
+ kind: literal("pulse"),
51133
+ cap: string().min(1),
51134
+ targetId: string().min(1),
51135
+ enabled: boolean(),
51136
+ debounceMs: number().nonnegative(),
51137
+ edges: array(_enum([
51138
+ "rising",
51139
+ "button",
51140
+ "native-event"
51141
+ ])).min(1).optional(),
51142
+ sources: array(OverrideSourceSchema).min(1)
51143
+ });
51144
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
51145
+ "in-addition",
51146
+ "confirm",
51147
+ "replace"
51148
+ ]).optional() });
51149
+ discriminatedUnion("kind", [
51150
+ ScalarOverrideDraftSchema,
51151
+ KeyedArrayOverrideDraftSchema,
51152
+ PulseOverrideDraftSchema,
51153
+ object({
51154
+ kind: literal("span"),
51155
+ cap: string().min(1),
51156
+ targetId: string().min(1),
51157
+ timeoutMs: number().nonnegative(),
51158
+ cooldownMs: number().nonnegative().optional(),
51159
+ sources: array(SpanSourceDraftSchema)
51160
+ })
51161
+ ]);
51162
+ object({
51163
+ targetId: string().min(1),
51164
+ configured: boolean(),
51165
+ source: _enum(["native", "assigned"]),
51166
+ state: _enum([
51167
+ "active",
51168
+ "stale",
51169
+ "released",
51170
+ "unavailable"
51171
+ ]),
51172
+ reason: string().nullable()
51173
+ });
51174
+ /**
51175
+ * What a running-threshold proposal says (planning#405). The schema is the
51176
+ * type: the algorithm, the capability method and the UI all read `z.infer`.
51177
+ *
51178
+ * A proposal is read-only advice: it carries the numbers it was derived from
51179
+ * (`evidence`) so the operator can judge it, and an `insufficient` answer names
51180
+ * WHY with a typed reason and the catalog defaults, never an invented number.
51181
+ */
51182
+ var RunningProposalTierSchema = _enum(["raw", "5m"]);
51183
+ var RunningProposalConfidenceSchema = _enum([
51184
+ "high",
51185
+ "medium",
51186
+ "low"
51187
+ ]);
51188
+ var RunningProposalInsufficientReasonSchema = _enum([
51189
+ "no-history",
51190
+ "span-too-short",
51191
+ "truncated",
51192
+ "no-idle-floor",
51193
+ "no-runs",
51194
+ "no-separation"
51195
+ ]);
51196
+ var RunningProposalReplaySchema = object({
51197
+ /** Intervals the real dwell expression held true over the window. */
51198
+ intervals: number().int().nonnegative(),
51199
+ /** Intervals outside every run, or a second interval inside one. */
51200
+ extra: number().int().nonnegative(),
51201
+ /** Runs without an interval of their own (none, or merged into a neighbour). */
51202
+ missed: number().int().nonnegative()
51203
+ });
51204
+ var RunningProposalEvidenceSchema = object({
51205
+ tier: RunningProposalTierSchema,
51206
+ spanMs: number().nonnegative(),
51207
+ from: number(),
51208
+ to: number(),
51209
+ points: number().int().nonnegative(),
51210
+ runsFound: number().int().nonnegative(),
51211
+ pausesFound: number().int().nonnegative(),
51212
+ longestPauseMs: number().nonnegative(),
51213
+ idleFloorW: number(),
51214
+ noiseCeilingW: number(),
51215
+ plateauW: number(),
51216
+ replay: RunningProposalReplaySchema
51217
+ });
51218
+ var RunningProposalInsufficientEvidenceSchema = object({
51219
+ spanMs: number().nonnegative(),
51220
+ points: number().int().nonnegative(),
51221
+ runsFound: number().int().nonnegative()
51222
+ });
51223
+ var RunningThresholdProposalSchema = discriminatedUnion("state", [object({
51224
+ state: literal("proposal"),
51225
+ transform: ThresholdTransformDraftSchema,
51226
+ evidence: RunningProposalEvidenceSchema,
51227
+ confidence: RunningProposalConfidenceSchema,
51228
+ /** Why the confidence is not higher; empty when nothing held it back. */
51229
+ notes: array(string())
51230
+ }), object({
51231
+ state: literal("insufficient"),
51232
+ reason: RunningProposalInsufficientReasonSchema,
51233
+ evidence: RunningProposalInsufficientEvidenceSchema,
51234
+ /** The catalog defaults, offered as what stands when nothing better is known. */
51235
+ fallback: ThresholdTransformDraftSchema
51236
+ })]);
51237
+ /**
50953
51238
  * The report of a one-shot "move this owner's plaintext secrets into the
50954
51239
  * keychain" run (D878). COUNTS only - never a value, never a ref.
50955
51240
  *
@@ -51246,6 +51531,14 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
51246
51531
  kind: "mutation",
51247
51532
  auth: "admin",
51248
51533
  access: "view"
51534
+ }), method(object({
51535
+ deviceId: number().int(),
51536
+ cap: string().min(1),
51537
+ fieldPath: string().min(1),
51538
+ deviceType: _enum(DeviceType).optional()
51539
+ }), RunningThresholdProposalSchema, {
51540
+ auth: "admin",
51541
+ access: "view"
51249
51542
  }), method(object({
51250
51543
  blockId: string().min(1),
51251
51544
  trace: AutomationRunTraceSchema.optional(),
@@ -55943,15 +56236,15 @@ var FanPresetCaptureResultSchema = object({
55943
56236
  items: array(FanCaptureItemSchema),
55944
56237
  omitted: array(FanCaptureOmissionSchema)
55945
56238
  });
55946
- var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
56239
+ var deviceInput$2 = object({ deviceId: number().int().nonnegative() });
55947
56240
  DeviceType.Fan;
55948
- method(deviceInput$1, array(FanPresetSchema), { auth: "protected" }), method(deviceInput$1.extend({ presets: array(FanPresetSchema).max(12) }), FanPresetsSetResultSchema, {
56241
+ method(deviceInput$2, array(FanPresetSchema), { auth: "protected" }), method(deviceInput$2.extend({ presets: array(FanPresetSchema).max(12) }), FanPresetsSetResultSchema, {
55949
56242
  kind: "mutation",
55950
56243
  auth: "admin"
55951
- }), method(deviceInput$1.extend({ presetId: string().min(1) }), FanPresetApplyResultSchema, {
56244
+ }), method(deviceInput$2.extend({ presetId: string().min(1) }), FanPresetApplyResultSchema, {
55952
56245
  kind: "mutation",
55953
56246
  auth: "protected"
55954
- }), method(deviceInput$1.extend({
56247
+ }), method(deviceInput$2.extend({
55955
56248
  fields: array(FanCaptureFieldSchema).optional(),
55956
56249
  steps: array(ActionStepSchema).max(20).default([])
55957
56250
  }), FanPresetCaptureResultSchema, { auth: "protected" });
@@ -59245,214 +59538,6 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
59245
59538
  ]);
59246
59539
  method(_void(), array(LoginMethodContributionSchema).readonly());
59247
59540
  /**
59248
- * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59249
- * Apple TV, Spotify, Roku, generic OTT receivers, …) on
59250
- * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
59251
- * surface — those use `DeviceType.Camera` + the broker pipeline.
59252
- *
59253
- * The cap declares a wide method surface; not every backend supports
59254
- * every method. Drivers signal sub-capability via the
59255
- * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
59256
- * corresponding method) so the UI gates buttons without a slice
59257
- * fetch — same pattern as `PanTiltZoom` for cameras.
59258
- */
59259
- var MediaPlayerStateSchema = _enum([
59260
- "off",
59261
- "on",
59262
- "idle",
59263
- "playing",
59264
- "paused",
59265
- "buffering",
59266
- "standby"
59267
- ]);
59268
- var MediaPlayerRepeatSchema = _enum([
59269
- "off",
59270
- "all",
59271
- "one"
59272
- ]);
59273
- var MediaInfoSchema = object({
59274
- /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
59275
- * `podcast`, …). */
59276
- type: string(),
59277
- /** Human-readable title. */
59278
- title: string(),
59279
- /** Optional artist / channel / station label. */
59280
- artist: string().optional(),
59281
- /** Optional album / season / show name. */
59282
- album: string().optional(),
59283
- /** Optional cover-art / thumbnail URL. */
59284
- imageUrl: string().optional()
59285
- });
59286
- /**
59287
- * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
59288
- * the device said so. `assumed`: the driver has no feedback (infrared) and
59289
- * tracks what it last SENT; it moves only after a send was accepted, and a
59290
- * human at the real remote makes it wrong. A UI shows an assumed value as a
59291
- * guess, never as a reading.
59292
- */
59293
- var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
59294
- /** The fields of a media-player status a driver can only guess. */
59295
- var MediaPlayerAssumedFieldSchema = _enum([
59296
- "state",
59297
- "volumeLevel",
59298
- "isMuted",
59299
- "source"
59300
- ]);
59301
- var MediaPlayerStatusSchema = object({
59302
- /** Playback lifecycle state. */
59303
- state: MediaPlayerStateSchema,
59304
- /**
59305
- * Whether the state fields are readings or the driver's own bookkeeping.
59306
- * A slice written before this field existed parses as `reported`.
59307
- */
59308
- stateSource: MediaPlayerStateSourceSchema.default("reported"),
59309
- /**
59310
- * Which fields are the driver's own guess. `stateSource` is `assumed` when
59311
- * this is not empty; a field not listed here is a reading even then (power
59312
- * from a running-state source, mute guessed from the last send).
59313
- */
59314
- assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
59315
- /** Volume as 0..100 inclusive. Null when the device has no volume
59316
- * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
59317
- volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59318
- /** Mute toggle distinct from volume=0. Null when no mute surface.
59319
- * Pair with `DeviceFeature.MediaPlayerMute`. */
59320
- isMuted: boolean().nullable(),
59321
- /** Active source / input. Empty when no source surface. */
59322
- source: string(),
59323
- /** Selectable sources. Empty when no source surface.
59324
- * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
59325
- availableSources: array(string()),
59326
- /** Currently-playing media info. Null when nothing is playing. */
59327
- currentMedia: MediaInfoSchema.nullable(),
59328
- /** Current playback position in ms. Null when not seekable or
59329
- * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
59330
- position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
59331
- /** Total duration of the current media in ms. Null when unknown
59332
- * (live stream) or nothing is playing. */
59333
- duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
59334
- /** Shuffle toggle. Null when no shuffle surface.
59335
- * Pair with `DeviceFeature.MediaPlayerShuffle`. */
59336
- shuffle: boolean().nullable(),
59337
- /** Repeat mode. Null when no repeat surface.
59338
- * Pair with `DeviceFeature.MediaPlayerRepeat`. */
59339
- repeat: MediaPlayerRepeatSchema.nullable(),
59340
- /** Ms epoch when the slice was last updated. */
59341
- lastChangedAt: number()
59342
- });
59343
- var mediaPlayerCapability = {
59344
- name: "media-player",
59345
- scope: "device",
59346
- deviceNative: true,
59347
- mode: "singleton",
59348
- deviceTypes: [DeviceType.MediaPlayer],
59349
- methods: {
59350
- play: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59351
- kind: "mutation",
59352
- auth: "protected"
59353
- }),
59354
- pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59355
- kind: "mutation",
59356
- auth: "protected"
59357
- }),
59358
- stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59359
- kind: "mutation",
59360
- auth: "protected"
59361
- }),
59362
- next: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59363
- kind: "mutation",
59364
- auth: "protected"
59365
- }),
59366
- previous: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59367
- kind: "mutation",
59368
- auth: "protected"
59369
- }),
59370
- seek: method(object({
59371
- deviceId: number().int().nonnegative(),
59372
- position: number().int().nonnegative()
59373
- }), _void(), {
59374
- kind: "mutation",
59375
- auth: "protected"
59376
- }),
59377
- setVolume: method(object({
59378
- deviceId: number().int().nonnegative(),
59379
- volumeLevel: number().min(0).max(100)
59380
- }), _void(), {
59381
- kind: "mutation",
59382
- auth: "protected"
59383
- }),
59384
- setMute: method(object({
59385
- deviceId: number().int().nonnegative(),
59386
- muted: boolean()
59387
- }), _void(), {
59388
- kind: "mutation",
59389
- auth: "protected"
59390
- }),
59391
- setShuffle: method(object({
59392
- deviceId: number().int().nonnegative(),
59393
- shuffle: boolean()
59394
- }), _void(), {
59395
- kind: "mutation",
59396
- auth: "protected"
59397
- }),
59398
- setRepeat: method(object({
59399
- deviceId: number().int().nonnegative(),
59400
- repeat: MediaPlayerRepeatSchema
59401
- }), _void(), {
59402
- kind: "mutation",
59403
- auth: "protected"
59404
- }),
59405
- selectSource: method(object({
59406
- deviceId: number().int().nonnegative(),
59407
- source: string().min(1)
59408
- }), _void(), {
59409
- kind: "mutation",
59410
- auth: "protected"
59411
- }),
59412
- playMedia: method(object({
59413
- deviceId: number().int().nonnegative(),
59414
- /** Media identifier / URL. */
59415
- mediaId: string().min(1),
59416
- /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
59417
- * passes it through to the upstream service. */
59418
- mediaType: string().min(1)
59419
- }), _void(), {
59420
- kind: "mutation",
59421
- auth: "protected"
59422
- })
59423
- },
59424
- status: {
59425
- schema: MediaPlayerStatusSchema,
59426
- kind: "push"
59427
- },
59428
- /**
59429
- * Runtime-state slice — mirrored by the kernel. UI players read the
59430
- * full slice for live now-playing, volume, and progress updates
59431
- * without polling.
59432
- */
59433
- runtimeState: MediaPlayerStatusSchema,
59434
- /**
59435
- * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
59436
- *
59437
- * See `RuntimeStateDurability`. Enforced by
59438
- * `scripts/check-runtime-state-durability.ts`.
59439
- */
59440
- durability: "session",
59441
- /**
59442
- * History (D850): volume (a level an operator or an automation sets; the
59443
- * default 10 s floor folds a slider drag into its end value) and mute.
59444
- * `position` is not recorded: it moves continuously while playing.
59445
- */
59446
- history: { fields: {
59447
- volumeLevel: {
59448
- kind: "gauge",
59449
- unit: "%",
59450
- deadband: 1
59451
- },
59452
- isMuted: { kind: "boolean" }
59453
- } }
59454
- };
59455
- /**
59456
59541
  * mesh-network — collection cap for mesh-VPN providers.
59457
59542
  *
59458
59543
  * Different shape from `network-access` (public tunnels):
@@ -73536,6 +73621,14 @@ var powerMeterCapability = {
73536
73621
  deviceNative: true,
73537
73622
  mode: "singleton",
73538
73623
  deviceTypes: POWER_METER_DEVICE_TYPES,
73624
+ deviceConfig: { ui: {
73625
+ kind: "widget",
73626
+ widgetId: "host/power-meter-line",
73627
+ tab: "power",
73628
+ placement: "hero",
73629
+ label: "Power",
73630
+ order: 4
73631
+ } },
73539
73632
  methods: {},
73540
73633
  status: {
73541
73634
  schema: PowerMeterStatusSchema,
@@ -73595,6 +73688,117 @@ var powerMeterCapability = {
73595
73688
  volatileStateFields: ["lastFetchedAt"],
73596
73689
  customize: powerMeterCustomize
73597
73690
  };
73691
+ var PowerSourceRefusalReasonSchema = _enum([
73692
+ "no-power-source",
73693
+ "switch-missing",
73694
+ "switch-offline",
73695
+ "switch-unknown",
73696
+ "restart-in-progress",
73697
+ "switch-call-failed"
73698
+ ]);
73699
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
73700
+ accepted: literal(false),
73701
+ reason: PowerSourceRefusalReasonSchema,
73702
+ /** One line for the operator, naming the switch. */
73703
+ message: string()
73704
+ })]);
73705
+ var PowerSourceInfoSchema = object({
73706
+ /** False when the device has no power source linked; the rest is then empty. */
73707
+ linked: boolean(),
73708
+ switchDeviceId: number().nullable(),
73709
+ switchName: string().nullable(),
73710
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
73711
+ switchOn: boolean().nullable(),
73712
+ switchOnline: boolean().nullable(),
73713
+ restartInProgress: boolean(),
73714
+ offSeconds: number().int()
73715
+ });
73716
+ /** The composed slice: the switch state the link mirrors, plus the stored off time. */
73717
+ var PowerSourceStateSchema = object({
73718
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
73719
+ switchOn: boolean().nullable(),
73720
+ offSeconds: number().int(),
73721
+ lastFetchedAt: number()
73722
+ });
73723
+ var POWER_SOURCE_DEVICE_TYPES = [
73724
+ DeviceType.Gateway,
73725
+ DeviceType.Hub,
73726
+ DeviceType.Camera,
73727
+ DeviceType.Sensor,
73728
+ DeviceType.MediaPlayer,
73729
+ DeviceType.Vacuum,
73730
+ DeviceType.Generic,
73731
+ DeviceType.Washer,
73732
+ DeviceType.Dryer,
73733
+ DeviceType.Dishwasher,
73734
+ DeviceType.PetFountain,
73735
+ DeviceType.Fan,
73736
+ DeviceType.Humidifier,
73737
+ DeviceType.Climate,
73738
+ DeviceType.WaterHeater
73739
+ ];
73740
+ var powerSourceCustomize = {
73741
+ version: 1,
73742
+ targets: [{
73743
+ id: "switch",
73744
+ cardinality: "scalar",
73745
+ vocabulary: {
73746
+ cap: "power-source",
73747
+ stateField: "switchOn"
73748
+ },
73749
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73750
+ apply: "add",
73751
+ path: "switchOn",
73752
+ sources: [{
73753
+ kind: "switch",
73754
+ transforms: [{ kind: "identity" }]
73755
+ }],
73756
+ companions: [{
73757
+ kind: "constant",
73758
+ path: "offSeconds",
73759
+ value: 10,
73760
+ when: "add"
73761
+ }, {
73762
+ kind: "clock",
73763
+ path: "lastFetchedAt",
73764
+ when: "always"
73765
+ }],
73766
+ sourceReport: { status: "assignment-status" }
73767
+ }]
73768
+ };
73769
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
73770
+ var powerSourceCapability = {
73771
+ name: "power-source",
73772
+ scope: "device",
73773
+ mode: "singleton",
73774
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73775
+ methods: {
73776
+ getStatus: systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }),
73777
+ powerOn: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
73778
+ kind: "mutation",
73779
+ auth: "admin"
73780
+ }),
73781
+ powerOff: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
73782
+ kind: "mutation",
73783
+ auth: "admin"
73784
+ }),
73785
+ forceRestart: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
73786
+ kind: "mutation",
73787
+ auth: "admin"
73788
+ })
73789
+ },
73790
+ runtimeState: PowerSourceStateSchema,
73791
+ customize: powerSourceCustomize,
73792
+ /**
73793
+ * Runtime-state durability: **session** — mirrored from the linked switch on
73794
+ * its next report; a restored value would outlive the reading it names.
73795
+ *
73796
+ * See `RuntimeStateDurability`. Enforced by
73797
+ * `scripts/check-runtime-state-durability.ts`.
73798
+ */
73799
+ durability: "session",
73800
+ history: "none"
73801
+ };
73598
73802
  /**
73599
73803
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
73600
73804
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -77129,7 +77333,13 @@ var RemoteMediaCommandSchema = _enum([
77129
77333
  "next",
77130
77334
  "previous",
77131
77335
  "setMute",
77132
- "selectSource"
77336
+ "selectSource",
77337
+ "turnOn",
77338
+ "turnOff",
77339
+ "volumeUp",
77340
+ "volumeDown",
77341
+ "channelUp",
77342
+ "channelDown"
77133
77343
  ]);
77134
77344
  /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
77135
77345
  var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
@@ -77150,7 +77360,7 @@ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.e
77150
77360
  }), RemoteSendResultSchema, {
77151
77361
  kind: "mutation",
77152
77362
  auth: "protected"
77153
- }), method(deviceInput.extend({
77363
+ }), method(deviceInput, MediaPlayerStatusSchema.nullable(), { auth: "protected" }), method(deviceInput.extend({
77154
77364
  command: RemoteMediaCommandSchema,
77155
77365
  muted: boolean().optional(),
77156
77366
  source: string().optional(),
@@ -79434,7 +79644,11 @@ listSignals: method(_void(), array(StreamSignalSchema).readonly()) }
79434
79644
  * `getSettingsUISchema()` surface.
79435
79645
  */
79436
79646
  var SwitchStatusSchema = object({
79437
- on: boolean().meta({ label: "On" }),
79647
+ /**
79648
+ * `null` = the device has never reported its state (a measurement that
79649
+ * has not happened is unknown, never `false`).
79650
+ */
79651
+ on: boolean().nullable().meta({ label: "On" }),
79438
79652
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
79439
79653
  lastChangedAt: number()
79440
79654
  });
@@ -79459,7 +79673,7 @@ var switchCapability = {
79459
79673
  }) },
79460
79674
  events: { onStateChanged: { data: object({
79461
79675
  deviceId: number(),
79462
- on: boolean(),
79676
+ on: boolean().nullable(),
79463
79677
  lastChangedAt: number()
79464
79678
  }) } },
79465
79679
  status: {
@@ -83062,6 +83276,7 @@ function buildEventKindDescriptor(kind, source) {
83062
83276
  }
83063
83277
  };
83064
83278
  }
83279
+ DeviceFeature.MediaPlayerPower, DeviceFeature.MediaPlayerVolumeStep, DeviceFeature.MediaPlayerChannelStep, DeviceFeature.MediaPlayerMute, DeviceFeature.MediaPlayerStop, DeviceFeature.MediaPlayerNext, DeviceFeature.MediaPlayerPrevious;
83065
83280
  var btn = (idSuffix, row, col, init) => ({
83066
83281
  idSuffix,
83067
83282
  row,
@@ -83188,6 +83403,34 @@ discriminatedUnion("kind", [object({
83188
83403
  kind: literal("pronto"),
83189
83404
  code: string()
83190
83405
  })]);
83406
+ /**
83407
+ * Propose a running threshold from a device's own power history (planning#405).
83408
+ *
83409
+ * Pure and deterministic: the same series gives the same answer. The series is
83410
+ * a HELD-VALUE step series — a point's value stands until the next point — which
83411
+ * is how device-history stores a gauge, so "time at a level" is exact, not a
83412
+ * count of samples.
83413
+ *
83414
+ * 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
83415
+ * near F. A device that is not near one level most of the time has no floor.
83416
+ * 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
83417
+ * 3. gaps between episodes split in two by the largest log-scale jump (>= 3x):
83418
+ * the short ones are pauses INSIDE a run (a soak), the long ones separate runs.
83419
+ * 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
83420
+ * grid a person would type; stop dwell covers the longest pause; start dwell
83421
+ * covers the longest standby blip above T.
83422
+ * 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
83423
+ * run must hold exactly one true interval and nothing may flap outside.
83424
+ */
83425
+ var SECOND_MS = 1e3;
83426
+ var MINUTE_MS$1 = 60 * SECOND_MS;
83427
+ 24 * (60 * MINUTE_MS$1);
83428
+ 10 * MINUTE_MS$1;
83429
+ 30 * SECOND_MS;
83430
+ 60 * SECOND_MS;
83431
+ 20 * MINUTE_MS$1;
83432
+ 10 * SECOND_MS;
83433
+ 10 * SECOND_MS;
83191
83434
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
83192
83435
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
83193
83436
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
@@ -85852,6 +86095,13 @@ Object.freeze({
85852
86095
  access: "create",
85853
86096
  role: "admin"
85854
86097
  },
86098
+ "coreBlocks.proposeRunningThreshold": {
86099
+ capName: "core-blocks",
86100
+ capScope: "system",
86101
+ addonId: null,
86102
+ access: "view",
86103
+ role: "admin"
86104
+ },
85855
86105
  "coreBlocks.reportAutomationRun": {
85856
86106
  capName: "core-blocks",
85857
86107
  capScope: "system",
@@ -88799,6 +89049,20 @@ Object.freeze({
88799
89049
  access: "view",
88800
89050
  role: "admin"
88801
89051
  },
89052
+ "mediaPlayer.channelDown": {
89053
+ capName: "media-player",
89054
+ capScope: "device",
89055
+ addonId: null,
89056
+ access: "create",
89057
+ role: "viewer"
89058
+ },
89059
+ "mediaPlayer.channelUp": {
89060
+ capName: "media-player",
89061
+ capScope: "device",
89062
+ addonId: null,
89063
+ access: "create",
89064
+ role: "viewer"
89065
+ },
88802
89066
  "mediaPlayer.getStatus": {
88803
89067
  capName: "media-player",
88804
89068
  capScope: "device",
@@ -88890,6 +89154,34 @@ Object.freeze({
88890
89154
  access: "create",
88891
89155
  role: "viewer"
88892
89156
  },
89157
+ "mediaPlayer.turnOff": {
89158
+ capName: "media-player",
89159
+ capScope: "device",
89160
+ addonId: null,
89161
+ access: "create",
89162
+ role: "viewer"
89163
+ },
89164
+ "mediaPlayer.turnOn": {
89165
+ capName: "media-player",
89166
+ capScope: "device",
89167
+ addonId: null,
89168
+ access: "create",
89169
+ role: "viewer"
89170
+ },
89171
+ "mediaPlayer.volumeDown": {
89172
+ capName: "media-player",
89173
+ capScope: "device",
89174
+ addonId: null,
89175
+ access: "create",
89176
+ role: "viewer"
89177
+ },
89178
+ "mediaPlayer.volumeUp": {
89179
+ capName: "media-player",
89180
+ capScope: "device",
89181
+ addonId: null,
89182
+ access: "create",
89183
+ role: "viewer"
89184
+ },
88893
89185
  "meshNetwork.getStatus": {
88894
89186
  capName: "mesh-network",
88895
89187
  capScope: "system",
@@ -92446,6 +92738,13 @@ Object.freeze({
92446
92738
  access: "create",
92447
92739
  role: "admin"
92448
92740
  },
92741
+ "remote.getAssumedStatus": {
92742
+ capName: "remote",
92743
+ capScope: "system",
92744
+ addonId: null,
92745
+ access: "view",
92746
+ role: "admin"
92747
+ },
92449
92748
  "remote.getConfig": {
92450
92749
  capName: "remote",
92451
92750
  capScope: "system",
@@ -95261,6 +95560,11 @@ Object.freeze({
95261
95560
  form: "single",
95262
95561
  optional: false
95263
95562
  }],
95563
+ "coreBlocks.proposeRunningThreshold": [{
95564
+ name: "deviceId",
95565
+ form: "single",
95566
+ optional: false
95567
+ }],
95264
95568
  "cover.close": [{
95265
95569
  name: "deviceId",
95266
95570
  form: "single",
@@ -96112,6 +96416,16 @@ Object.freeze({
96112
96416
  form: "single",
96113
96417
  optional: true
96114
96418
  }],
96419
+ "mediaPlayer.channelDown": [{
96420
+ name: "deviceId",
96421
+ form: "single",
96422
+ optional: false
96423
+ }],
96424
+ "mediaPlayer.channelUp": [{
96425
+ name: "deviceId",
96426
+ form: "single",
96427
+ optional: false
96428
+ }],
96115
96429
  "mediaPlayer.getStatus": [{
96116
96430
  name: "deviceId",
96117
96431
  form: "single",
@@ -96177,6 +96491,26 @@ Object.freeze({
96177
96491
  form: "single",
96178
96492
  optional: false
96179
96493
  }],
96494
+ "mediaPlayer.turnOff": [{
96495
+ name: "deviceId",
96496
+ form: "single",
96497
+ optional: false
96498
+ }],
96499
+ "mediaPlayer.turnOn": [{
96500
+ name: "deviceId",
96501
+ form: "single",
96502
+ optional: false
96503
+ }],
96504
+ "mediaPlayer.volumeDown": [{
96505
+ name: "deviceId",
96506
+ form: "single",
96507
+ optional: false
96508
+ }],
96509
+ "mediaPlayer.volumeUp": [{
96510
+ name: "deviceId",
96511
+ form: "single",
96512
+ optional: false
96513
+ }],
96180
96514
  "meter.getStatus": [{
96181
96515
  name: "deviceId",
96182
96516
  form: "single",
@@ -97342,6 +97676,11 @@ Object.freeze({
97342
97676
  form: "single",
97343
97677
  optional: true
97344
97678
  }],
97679
+ "remote.getAssumedStatus": [{
97680
+ name: "deviceId",
97681
+ form: "single",
97682
+ optional: false
97683
+ }],
97345
97684
  "remote.getConfig": [{
97346
97685
  name: "deviceId",
97347
97686
  form: "single",
@@ -97986,99 +98325,6 @@ var BucketAccumulator = class {
97986
98325
  return n;
97987
98326
  }
97988
98327
  };
97989
- /**
97990
- * A saved Customize assignment (D936). The schema is the type: callers use
97991
- * `z.infer`, they do not restate the shape.
97992
- */
97993
- var OverrideSourceSchema = object({
97994
- addonId: string().min(1),
97995
- stableId: string().min(1),
97996
- cap: string().min(1),
97997
- fieldPath: string().min(1)
97998
- });
97999
- var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
98000
- object({ kind: literal("identity") }),
98001
- object({ kind: literal("invert") }),
98002
- object({
98003
- kind: literal("threshold"),
98004
- comparison: _enum(["gte", "lte"]),
98005
- threshold: number(),
98006
- startDwellMs: number().nonnegative(),
98007
- stopDwellMs: number().nonnegative()
98008
- }),
98009
- object({
98010
- kind: literal("linear"),
98011
- scale: number(),
98012
- offset: number(),
98013
- clampMin: number().optional(),
98014
- clampMax: number().optional()
98015
- }),
98016
- object({
98017
- kind: literal("enum-map"),
98018
- mapping: record(string(), string().nullable())
98019
- }),
98020
- object({ kind: literal("number") })
98021
- ]);
98022
- var ScalarOverrideDraftSchema = object({
98023
- kind: literal("scalar"),
98024
- cap: string().min(1),
98025
- targetId: string().min(1),
98026
- source: OverrideSourceSchema,
98027
- transform: CustomizeTransformDraftSchema
98028
- });
98029
- var KeyedArrayOverrideDraftSchema = object({
98030
- kind: literal("keyedArray"),
98031
- cap: string().min(1),
98032
- targetId: string().min(1),
98033
- key: string().min(1),
98034
- label: string().min(1),
98035
- fieldPath: string().min(1),
98036
- source: OverrideSourceSchema,
98037
- transform: CustomizeTransformDraftSchema
98038
- });
98039
- var PulseOverrideDraftSchema = object({
98040
- kind: literal("pulse"),
98041
- cap: string().min(1),
98042
- targetId: string().min(1),
98043
- enabled: boolean(),
98044
- debounceMs: number().nonnegative(),
98045
- edges: array(_enum([
98046
- "rising",
98047
- "button",
98048
- "native-event"
98049
- ])).min(1).optional(),
98050
- sources: array(OverrideSourceSchema).min(1)
98051
- });
98052
- var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
98053
- "in-addition",
98054
- "confirm",
98055
- "replace"
98056
- ]).optional() });
98057
- discriminatedUnion("kind", [
98058
- ScalarOverrideDraftSchema,
98059
- KeyedArrayOverrideDraftSchema,
98060
- PulseOverrideDraftSchema,
98061
- object({
98062
- kind: literal("span"),
98063
- cap: string().min(1),
98064
- targetId: string().min(1),
98065
- timeoutMs: number().nonnegative(),
98066
- cooldownMs: number().nonnegative().optional(),
98067
- sources: array(SpanSourceDraftSchema)
98068
- })
98069
- ]);
98070
- object({
98071
- targetId: string().min(1),
98072
- configured: boolean(),
98073
- source: _enum(["native", "assigned"]),
98074
- state: _enum([
98075
- "active",
98076
- "stale",
98077
- "released",
98078
- "unavailable"
98079
- ]),
98080
- reason: string().nullable()
98081
- });
98082
98328
  var G711_SCALE_CORRECTION_DB = {
98083
98329
  PCMU: 20 * Math.log10(4),
98084
98330
  PCMA: 20 * Math.log10(8)