@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
@@ -785,7 +785,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
785
785
  return EventCategory;
786
786
  }({});
787
787
  //#endregion
788
- //#region ../types/dist/device-type-CfHw_quR.mjs
788
+ //#region ../types/dist/device-type-D1fH5kaC.mjs
789
789
  /**
790
790
  import { errMsg } from '@camstack/types'
791
791
  * Extract a human-readable message from an unknown error value.
@@ -1016,6 +1016,12 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
1016
1016
  DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
1017
1017
  /** Media player exposes stop distinct from pause. */
1018
1018
  DeviceFeature["MediaPlayerStop"] = "media-player-stop";
1019
+ /** Media player exposes volume up / down in steps (an infrared TV has no level). */
1020
+ DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
1021
+ /** Media player exposes channel up / down in steps. */
1022
+ DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
1023
+ /** Media player exposes power on / off. */
1024
+ DeviceFeature["MediaPlayerPower"] = "media-player-power";
1019
1025
  /** Alarm panel requires a PIN code on arm/disarm. */
1020
1026
  DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
1021
1027
  /** Presence device carries GPS coordinates (lat/lng/accuracy) in
@@ -6032,7 +6038,7 @@ var ZodIssueCode = {
6032
6038
  var ZodFirstPartyTypeKind;
6033
6039
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6034
6040
  //#endregion
6035
- //#region ../types/dist/sleep-C6LqREpb.mjs
6041
+ //#region ../types/dist/sleep-hK-Dss3z.mjs
6036
6042
  /**
6037
6043
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6038
6044
  * window to float samples (D455).
@@ -8120,6 +8126,10 @@ var BaseAddon = class {
8120
8126
  const stored = keychain ? await this.readAddonStoreWithRetry() : {};
8121
8127
  const patch = {};
8122
8128
  for (const key of keys) {
8129
+ if (tree.get(key)?.kind === "array") {
8130
+ patch[key] = [];
8131
+ continue;
8132
+ }
8123
8133
  const keychainStored = tree.has(key) || collectSecretMarkerRefs(stored[key]).length > 0;
8124
8134
  patch[key] = keychain && keychainStored ? SECRET_CLEAR : "";
8125
8135
  }
@@ -11968,7 +11978,7 @@ function sleep(ms) {
11968
11978
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
11969
11979
  }
11970
11980
  //#endregion
11971
- //#region ../types/dist/composition-Dh3RfMx5.mjs
11981
+ //#region ../types/dist/composition-BSGHhcr8.mjs
11972
11982
  /**
11973
11983
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
11974
11984
  * canonical form sorts object keys alphabetically at every depth so two
@@ -12891,38 +12901,6 @@ function validateExpressionSource(src) {
12891
12901
  return null;
12892
12902
  }
12893
12903
  /**
12894
- * One power reading becomes a washer, dryer or dishwasher (D944 helper).
12895
- *
12896
- * Standby of the control board is under 5 W; a motor or a heater is far
12897
- * above that, so 5 W is the line. A door lock or a short pump spike is not
12898
- * a cycle, so running starts only after 30 s above the line.
12899
- *
12900
- * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
12901
- * bursts) lasts several minutes. Ending the cycle on the first dip would
12902
- * report "finished" in the middle of the program, so the stop dwell is
12903
- * 10 minutes on every type. The number is stored per type so one machine
12904
- * can move later without moving the others.
12905
- */
12906
- var APPLIANCE_TEMPLATE_ID = "appliance";
12907
- var APPLIANCE_KINDS = [
12908
- "washer",
12909
- "dryer",
12910
- "dishwasher"
12911
- ];
12912
- DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
12913
- /**
12914
- * A dumb plug-in stove or heater, built from a smart plug (a `Heater`).
12915
- *
12916
- * The plug is the actuator: `switch.setState` is a FORWARD to the plug's own
12917
- * (D967), so the heater switches exactly as the plug does. Running is the
12918
- * plug being on; when a power reading is also named, running is the draw
12919
- * staying above the line instead (a plug left on with the stove's own
12920
- * thermostat open is not heating). 50 W is far above any standby and below
12921
- * the smallest radiator.
12922
- */
12923
- var HEATER_TEMPLATE_ID = "heater";
12924
- DeviceType.Heater;
12925
- /**
12926
12904
  * Statistics and integrals over a history read (D944).
12927
12905
  *
12928
12906
  * Pure: the same points always give the same answer, so a restart recomputes
@@ -13066,34 +13044,6 @@ var HelperSpecSchema = discriminatedUnion("kind", [
13066
13044
  /** Actuator groups only. Readings leave this unset. */
13067
13045
  active: ActiveCriterionSchema.optional()
13068
13046
  }),
13069
- object({
13070
- kind: literal("appliance"),
13071
- templateId: literal(APPLIANCE_TEMPLATE_ID),
13072
- appliance: _enum(APPLIANCE_KINDS),
13073
- thresholdWatts: number().positive(),
13074
- startDwellMs: number().int().nonnegative(),
13075
- stopDwellMs: number().int().nonnegative(),
13076
- member: HelperMemberSchema,
13077
- /**
13078
- * The plug that powers the appliance (`switch.on`). Optional: when set, the
13079
- * composition carries a `power-source` feature, so the hub can cut and restore
13080
- * that plug (power-source link of a NEW-target composition).
13081
- */
13082
- powerSwitch: HelperMemberSchema.optional(),
13083
- /** How long a forced restart keeps the plug off; the cap's default when unset. */
13084
- offSeconds: number().optional()
13085
- }),
13086
- object({
13087
- kind: literal("heater"),
13088
- templateId: literal(HEATER_TEMPLATE_ID),
13089
- /** The plug, read and commanded at `switch.on`. */
13090
- plug: HelperMemberSchema,
13091
- /** The plug's power reading, when it has one: running is then the draw, not the switch. */
13092
- meter: HelperMemberSchema.optional(),
13093
- thresholdWatts: number().positive(),
13094
- startDwellMs: number().int().nonnegative(),
13095
- stopDwellMs: number().int().nonnegative()
13096
- }),
13097
13047
  object({
13098
13048
  kind: literal("statistic"),
13099
13049
  stat: _enum(STATISTIC_STATS),
@@ -13265,7 +13215,14 @@ var CompositionForwardCommandSchema = object({
13265
13215
  method: string().min(1),
13266
13216
  args: record(string().min(1), CompositionForwardArgSchema).optional()
13267
13217
  });
13268
- var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
13218
+ var CompositionCommandTargetSchema = discriminatedUnion("kind", [
13219
+ CompositionForwardCommandSchema,
13220
+ CompositionCodeSourceSchema,
13221
+ object({
13222
+ kind: literal("extension"),
13223
+ target: literal("remote")
13224
+ })
13225
+ ]);
13269
13226
  /** An item key inside an item-array cap (`consumables.items[<key>]`). */
13270
13227
  var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
13271
13228
  /**
@@ -13310,7 +13267,7 @@ var CompositionSchema = object({
13310
13267
  kind: literal("existing"),
13311
13268
  device: CompositionSourceRefSchema
13312
13269
  })]),
13313
- features: array(CompositionFeatureSchema).min(1).max(16),
13270
+ features: array(CompositionFeatureSchema).min(0).max(16),
13314
13271
  /**
13315
13272
  * Present when the block is a helper template. Absent on a free
13316
13273
  * composition (the room example, device 4603). The editor reads this,
@@ -20532,6 +20489,48 @@ var APPLIANCE_CAP_VOCABULARY = {
20532
20489
  scope: "device",
20533
20490
  noun: t("Media player", "Lettore multimediale"),
20534
20491
  actions: [
20492
+ {
20493
+ id: "media.turnOn",
20494
+ method: "turnOn",
20495
+ label: t("Turn on", "Accendi"),
20496
+ phrase: t("Turn on {device}", "Accendi {device}"),
20497
+ icon: "power"
20498
+ },
20499
+ {
20500
+ id: "media.turnOff",
20501
+ method: "turnOff",
20502
+ label: t("Turn off", "Spegni"),
20503
+ phrase: t("Turn off {device}", "Spegni {device}"),
20504
+ icon: "power"
20505
+ },
20506
+ {
20507
+ id: "media.volumeUp",
20508
+ method: "volumeUp",
20509
+ label: t("Volume up", "Alza il volume"),
20510
+ phrase: t("Raise the volume of {device}", "Alza il volume di {device}"),
20511
+ icon: "volume-2"
20512
+ },
20513
+ {
20514
+ id: "media.volumeDown",
20515
+ method: "volumeDown",
20516
+ label: t("Volume down", "Abbassa il volume"),
20517
+ phrase: t("Lower the volume of {device}", "Abbassa il volume di {device}"),
20518
+ icon: "volume-2"
20519
+ },
20520
+ {
20521
+ id: "media.channelUp",
20522
+ method: "channelUp",
20523
+ label: t("Channel up", "Canale successivo"),
20524
+ phrase: t("Go to the next channel on {device}", "Passa al canale successivo su {device}"),
20525
+ icon: "skip-forward"
20526
+ },
20527
+ {
20528
+ id: "media.channelDown",
20529
+ method: "channelDown",
20530
+ label: t("Channel down", "Canale precedente"),
20531
+ phrase: t("Go to the previous channel on {device}", "Torna al canale precedente su {device}"),
20532
+ icon: "skip-back"
20533
+ },
20535
20534
  {
20536
20535
  id: "media.play",
20537
20536
  method: "play",
@@ -50334,6 +50333,244 @@ var controlCapability = {
50334
50333
  */
50335
50334
  history: "none"
50336
50335
  };
50336
+ /**
50337
+ * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
50338
+ * Apple TV, Spotify, Roku, generic OTT receivers, …) on
50339
+ * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
50340
+ * surface — those use `DeviceType.Camera` + the broker pipeline.
50341
+ *
50342
+ * The cap declares a wide method surface; not every backend supports
50343
+ * every method. Drivers signal sub-capability via the
50344
+ * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
50345
+ * corresponding method) so the UI gates buttons without a slice
50346
+ * fetch — same pattern as `PanTiltZoom` for cameras.
50347
+ */
50348
+ var MediaPlayerStateSchema = _enum([
50349
+ "off",
50350
+ "on",
50351
+ "idle",
50352
+ "playing",
50353
+ "paused",
50354
+ "buffering",
50355
+ "standby"
50356
+ ]);
50357
+ var MediaPlayerRepeatSchema = _enum([
50358
+ "off",
50359
+ "all",
50360
+ "one"
50361
+ ]);
50362
+ var MediaInfoSchema = object({
50363
+ /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
50364
+ * `podcast`, …). */
50365
+ type: string(),
50366
+ /** Human-readable title. */
50367
+ title: string(),
50368
+ /** Optional artist / channel / station label. */
50369
+ artist: string().optional(),
50370
+ /** Optional album / season / show name. */
50371
+ album: string().optional(),
50372
+ /** Optional cover-art / thumbnail URL. */
50373
+ imageUrl: string().optional()
50374
+ });
50375
+ /**
50376
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
50377
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
50378
+ * tracks what it last SENT; it moves only after a send was accepted, and a
50379
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
50380
+ * guess, never as a reading.
50381
+ */
50382
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
50383
+ /** The fields of a media-player status a driver can only guess. */
50384
+ var MediaPlayerAssumedFieldSchema = _enum([
50385
+ "state",
50386
+ "volumeLevel",
50387
+ "isMuted",
50388
+ "source"
50389
+ ]);
50390
+ var MediaPlayerStatusSchema = object({
50391
+ /** Playback lifecycle state. */
50392
+ state: MediaPlayerStateSchema,
50393
+ /**
50394
+ * Whether the state fields are readings or the driver's own bookkeeping.
50395
+ * A slice written before this field existed parses as `reported`.
50396
+ */
50397
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
50398
+ /**
50399
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
50400
+ * this is not empty; a field not listed here is a reading even then (power
50401
+ * from a running-state source, mute guessed from the last send).
50402
+ */
50403
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
50404
+ /** Volume as 0..100 inclusive. Null when the device has no volume
50405
+ * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
50406
+ volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
50407
+ /** Mute toggle distinct from volume=0. Null when no mute surface.
50408
+ * Pair with `DeviceFeature.MediaPlayerMute`. */
50409
+ isMuted: boolean().nullable(),
50410
+ /** Active source / input. Empty when no source surface. */
50411
+ source: string(),
50412
+ /** Selectable sources. Empty when no source surface.
50413
+ * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
50414
+ availableSources: array(string()),
50415
+ /** Currently-playing media info. Null when nothing is playing. */
50416
+ currentMedia: MediaInfoSchema.nullable(),
50417
+ /** Current playback position in ms. Null when not seekable or
50418
+ * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
50419
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
50420
+ /** Total duration of the current media in ms. Null when unknown
50421
+ * (live stream) or nothing is playing. */
50422
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
50423
+ /** Shuffle toggle. Null when no shuffle surface.
50424
+ * Pair with `DeviceFeature.MediaPlayerShuffle`. */
50425
+ shuffle: boolean().nullable(),
50426
+ /** Repeat mode. Null when no repeat surface.
50427
+ * Pair with `DeviceFeature.MediaPlayerRepeat`. */
50428
+ repeat: MediaPlayerRepeatSchema.nullable(),
50429
+ /** Ms epoch when the slice was last updated. */
50430
+ lastChangedAt: number()
50431
+ });
50432
+ var stepInput = object({
50433
+ deviceId: number().int().nonnegative(),
50434
+ /** How many presses: the caller's count (Alexa `volumeSteps`, `channelCount`). */
50435
+ steps: number().int().min(1).max(50).default(1)
50436
+ });
50437
+ var deviceOnly = object({ deviceId: number().int().nonnegative() });
50438
+ var mediaPlayerCapability = {
50439
+ name: "media-player",
50440
+ scope: "device",
50441
+ deviceNative: true,
50442
+ mode: "singleton",
50443
+ deviceTypes: [DeviceType.MediaPlayer],
50444
+ methods: {
50445
+ turnOn: method(deviceOnly, _void(), {
50446
+ kind: "mutation",
50447
+ auth: "protected"
50448
+ }),
50449
+ turnOff: method(deviceOnly, _void(), {
50450
+ kind: "mutation",
50451
+ auth: "protected"
50452
+ }),
50453
+ volumeUp: method(stepInput, _void(), {
50454
+ kind: "mutation",
50455
+ auth: "protected"
50456
+ }),
50457
+ volumeDown: method(stepInput, _void(), {
50458
+ kind: "mutation",
50459
+ auth: "protected"
50460
+ }),
50461
+ channelUp: method(stepInput, _void(), {
50462
+ kind: "mutation",
50463
+ auth: "protected"
50464
+ }),
50465
+ channelDown: method(stepInput, _void(), {
50466
+ kind: "mutation",
50467
+ auth: "protected"
50468
+ }),
50469
+ play: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50470
+ kind: "mutation",
50471
+ auth: "protected"
50472
+ }),
50473
+ pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50474
+ kind: "mutation",
50475
+ auth: "protected"
50476
+ }),
50477
+ stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50478
+ kind: "mutation",
50479
+ auth: "protected"
50480
+ }),
50481
+ next: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50482
+ kind: "mutation",
50483
+ auth: "protected"
50484
+ }),
50485
+ previous: method(object({ deviceId: number().int().nonnegative() }), _void(), {
50486
+ kind: "mutation",
50487
+ auth: "protected"
50488
+ }),
50489
+ seek: method(object({
50490
+ deviceId: number().int().nonnegative(),
50491
+ position: number().int().nonnegative()
50492
+ }), _void(), {
50493
+ kind: "mutation",
50494
+ auth: "protected"
50495
+ }),
50496
+ setVolume: method(object({
50497
+ deviceId: number().int().nonnegative(),
50498
+ volumeLevel: number().min(0).max(100)
50499
+ }), _void(), {
50500
+ kind: "mutation",
50501
+ auth: "protected"
50502
+ }),
50503
+ setMute: method(object({
50504
+ deviceId: number().int().nonnegative(),
50505
+ muted: boolean()
50506
+ }), _void(), {
50507
+ kind: "mutation",
50508
+ auth: "protected"
50509
+ }),
50510
+ setShuffle: method(object({
50511
+ deviceId: number().int().nonnegative(),
50512
+ shuffle: boolean()
50513
+ }), _void(), {
50514
+ kind: "mutation",
50515
+ auth: "protected"
50516
+ }),
50517
+ setRepeat: method(object({
50518
+ deviceId: number().int().nonnegative(),
50519
+ repeat: MediaPlayerRepeatSchema
50520
+ }), _void(), {
50521
+ kind: "mutation",
50522
+ auth: "protected"
50523
+ }),
50524
+ selectSource: method(object({
50525
+ deviceId: number().int().nonnegative(),
50526
+ source: string().min(1)
50527
+ }), _void(), {
50528
+ kind: "mutation",
50529
+ auth: "protected"
50530
+ }),
50531
+ playMedia: method(object({
50532
+ deviceId: number().int().nonnegative(),
50533
+ /** Media identifier / URL. */
50534
+ mediaId: string().min(1),
50535
+ /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
50536
+ * passes it through to the upstream service. */
50537
+ mediaType: string().min(1)
50538
+ }), _void(), {
50539
+ kind: "mutation",
50540
+ auth: "protected"
50541
+ })
50542
+ },
50543
+ status: {
50544
+ schema: MediaPlayerStatusSchema,
50545
+ kind: "push"
50546
+ },
50547
+ /**
50548
+ * Runtime-state slice — mirrored by the kernel. UI players read the
50549
+ * full slice for live now-playing, volume, and progress updates
50550
+ * without polling.
50551
+ */
50552
+ runtimeState: MediaPlayerStatusSchema,
50553
+ /**
50554
+ * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
50555
+ *
50556
+ * See `RuntimeStateDurability`. Enforced by
50557
+ * `scripts/check-runtime-state-durability.ts`.
50558
+ */
50559
+ durability: "session",
50560
+ /**
50561
+ * History (D850): volume (a level an operator or an automation sets; the
50562
+ * default 10 s floor folds a slider drag into its end value) and mute.
50563
+ * `position` is not recorded: it moves continuously while playing.
50564
+ */
50565
+ history: { fields: {
50566
+ volumeLevel: {
50567
+ kind: "gauge",
50568
+ unit: "%",
50569
+ deadband: 1
50570
+ },
50571
+ isMuted: { kind: "boolean" }
50572
+ } }
50573
+ };
50337
50574
  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;
50338
50575
  var NUMBER = {
50339
50576
  kind: "fixed",
@@ -50781,117 +51018,6 @@ function actuator(input) {
50781
51018
  };
50782
51019
  }
50783
51020
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
50784
- var PowerSourceRefusalReasonSchema = _enum([
50785
- "no-power-source",
50786
- "switch-missing",
50787
- "switch-offline",
50788
- "switch-unknown",
50789
- "restart-in-progress",
50790
- "switch-call-failed"
50791
- ]);
50792
- var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
50793
- accepted: literal(false),
50794
- reason: PowerSourceRefusalReasonSchema,
50795
- /** One line for the operator, naming the switch. */
50796
- message: string()
50797
- })]);
50798
- var PowerSourceInfoSchema = object({
50799
- /** False when the device has no power source linked; the rest is then empty. */
50800
- linked: boolean(),
50801
- switchDeviceId: number().nullable(),
50802
- switchName: string().nullable(),
50803
- /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
50804
- switchOn: boolean().nullable(),
50805
- switchOnline: boolean().nullable(),
50806
- restartInProgress: boolean(),
50807
- offSeconds: number().int()
50808
- });
50809
- /** The composed slice: the switch state the link mirrors, plus the stored off time. */
50810
- var PowerSourceStateSchema = object({
50811
- /** Null while the switch has not reported: unknown is never `false` (D393). */
50812
- switchOn: boolean().nullable(),
50813
- offSeconds: number().int(),
50814
- lastFetchedAt: number()
50815
- });
50816
- var POWER_SOURCE_DEVICE_TYPES = [
50817
- DeviceType.Gateway,
50818
- DeviceType.Hub,
50819
- DeviceType.Camera,
50820
- DeviceType.Sensor,
50821
- DeviceType.MediaPlayer,
50822
- DeviceType.Vacuum,
50823
- DeviceType.Generic,
50824
- DeviceType.Washer,
50825
- DeviceType.Dryer,
50826
- DeviceType.Dishwasher,
50827
- DeviceType.PetFountain,
50828
- DeviceType.Fan,
50829
- DeviceType.Humidifier,
50830
- DeviceType.Climate,
50831
- DeviceType.WaterHeater
50832
- ];
50833
- var powerSourceCustomize = {
50834
- version: 1,
50835
- targets: [{
50836
- id: "switch",
50837
- cardinality: "scalar",
50838
- vocabulary: {
50839
- cap: "power-source",
50840
- stateField: "switchOn"
50841
- },
50842
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
50843
- apply: "add",
50844
- path: "switchOn",
50845
- sources: [{
50846
- kind: "switch",
50847
- transforms: [{ kind: "identity" }]
50848
- }],
50849
- companions: [{
50850
- kind: "constant",
50851
- path: "offSeconds",
50852
- value: 10,
50853
- when: "add"
50854
- }, {
50855
- kind: "clock",
50856
- path: "lastFetchedAt",
50857
- when: "always"
50858
- }],
50859
- sourceReport: { status: "assignment-status" }
50860
- }]
50861
- };
50862
- var deviceInput$2 = object({ deviceId: number().int().nonnegative() });
50863
- var powerSourceCapability = {
50864
- name: "power-source",
50865
- scope: "device",
50866
- mode: "singleton",
50867
- deviceTypes: POWER_SOURCE_DEVICE_TYPES,
50868
- methods: {
50869
- getStatus: systemMethod(deviceInput$2, PowerSourceInfoSchema, { auth: "admin" }),
50870
- powerOn: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
50871
- kind: "mutation",
50872
- auth: "admin"
50873
- }),
50874
- powerOff: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
50875
- kind: "mutation",
50876
- auth: "admin"
50877
- }),
50878
- forceRestart: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
50879
- kind: "mutation",
50880
- auth: "admin"
50881
- })
50882
- },
50883
- runtimeState: PowerSourceStateSchema,
50884
- customize: powerSourceCustomize,
50885
- /**
50886
- * Runtime-state durability: **session** — mirrored from the linked switch on
50887
- * its next report; a restored value would outlive the reading it names.
50888
- *
50889
- * See `RuntimeStateDurability`. Enforced by
50890
- * `scripts/check-runtime-state-durability.ts`.
50891
- */
50892
- durability: "session",
50893
- history: "none"
50894
- };
50895
51021
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
50896
51022
  DeviceType.Camera;
50897
51023
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
@@ -50919,6 +51045,165 @@ var ComposableCapabilitiesSchema = object({ caps: array(object({
50919
51045
  }).optional()
50920
51046
  })) });
50921
51047
  /**
51048
+ * A saved Customize assignment (D936). The schema is the type: callers use
51049
+ * `z.infer`, they do not restate the shape.
51050
+ */
51051
+ var OverrideSourceSchema = object({
51052
+ addonId: string().min(1),
51053
+ stableId: string().min(1),
51054
+ cap: string().min(1),
51055
+ fieldPath: string().min(1)
51056
+ });
51057
+ var IdentityTransformDraftSchema = object({ kind: literal("identity") });
51058
+ var InvertTransformDraftSchema = object({ kind: literal("invert") });
51059
+ var ThresholdTransformDraftSchema = object({
51060
+ kind: literal("threshold"),
51061
+ comparison: _enum(["gte", "lte"]),
51062
+ threshold: number(),
51063
+ startDwellMs: number().nonnegative(),
51064
+ stopDwellMs: number().nonnegative()
51065
+ });
51066
+ var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
51067
+ IdentityTransformDraftSchema,
51068
+ InvertTransformDraftSchema,
51069
+ ThresholdTransformDraftSchema,
51070
+ object({
51071
+ kind: literal("linear"),
51072
+ scale: number(),
51073
+ offset: number(),
51074
+ clampMin: number().optional(),
51075
+ clampMax: number().optional()
51076
+ }),
51077
+ object({
51078
+ kind: literal("enum-map"),
51079
+ mapping: record(string(), string().nullable())
51080
+ }),
51081
+ object({ kind: literal("number") })
51082
+ ]);
51083
+ var ScalarOverrideDraftSchema = object({
51084
+ kind: literal("scalar"),
51085
+ cap: string().min(1),
51086
+ targetId: string().min(1),
51087
+ source: OverrideSourceSchema,
51088
+ transform: CustomizeTransformDraftSchema
51089
+ });
51090
+ var KeyedArrayOverrideDraftSchema = object({
51091
+ kind: literal("keyedArray"),
51092
+ cap: string().min(1),
51093
+ targetId: string().min(1),
51094
+ key: string().min(1),
51095
+ label: string().min(1),
51096
+ fieldPath: string().min(1),
51097
+ source: OverrideSourceSchema,
51098
+ transform: CustomizeTransformDraftSchema
51099
+ });
51100
+ var PulseOverrideDraftSchema = object({
51101
+ kind: literal("pulse"),
51102
+ cap: string().min(1),
51103
+ targetId: string().min(1),
51104
+ enabled: boolean(),
51105
+ debounceMs: number().nonnegative(),
51106
+ edges: array(_enum([
51107
+ "rising",
51108
+ "button",
51109
+ "native-event"
51110
+ ])).min(1).optional(),
51111
+ sources: array(OverrideSourceSchema).min(1)
51112
+ });
51113
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
51114
+ "in-addition",
51115
+ "confirm",
51116
+ "replace"
51117
+ ]).optional() });
51118
+ discriminatedUnion("kind", [
51119
+ ScalarOverrideDraftSchema,
51120
+ KeyedArrayOverrideDraftSchema,
51121
+ PulseOverrideDraftSchema,
51122
+ object({
51123
+ kind: literal("span"),
51124
+ cap: string().min(1),
51125
+ targetId: string().min(1),
51126
+ timeoutMs: number().nonnegative(),
51127
+ cooldownMs: number().nonnegative().optional(),
51128
+ sources: array(SpanSourceDraftSchema)
51129
+ })
51130
+ ]);
51131
+ object({
51132
+ targetId: string().min(1),
51133
+ configured: boolean(),
51134
+ source: _enum(["native", "assigned"]),
51135
+ state: _enum([
51136
+ "active",
51137
+ "stale",
51138
+ "released",
51139
+ "unavailable"
51140
+ ]),
51141
+ reason: string().nullable()
51142
+ });
51143
+ /**
51144
+ * What a running-threshold proposal says (planning#405). The schema is the
51145
+ * type: the algorithm, the capability method and the UI all read `z.infer`.
51146
+ *
51147
+ * A proposal is read-only advice: it carries the numbers it was derived from
51148
+ * (`evidence`) so the operator can judge it, and an `insufficient` answer names
51149
+ * WHY with a typed reason and the catalog defaults, never an invented number.
51150
+ */
51151
+ var RunningProposalTierSchema = _enum(["raw", "5m"]);
51152
+ var RunningProposalConfidenceSchema = _enum([
51153
+ "high",
51154
+ "medium",
51155
+ "low"
51156
+ ]);
51157
+ var RunningProposalInsufficientReasonSchema = _enum([
51158
+ "no-history",
51159
+ "span-too-short",
51160
+ "truncated",
51161
+ "no-idle-floor",
51162
+ "no-runs",
51163
+ "no-separation"
51164
+ ]);
51165
+ var RunningProposalReplaySchema = object({
51166
+ /** Intervals the real dwell expression held true over the window. */
51167
+ intervals: number().int().nonnegative(),
51168
+ /** Intervals outside every run, or a second interval inside one. */
51169
+ extra: number().int().nonnegative(),
51170
+ /** Runs without an interval of their own (none, or merged into a neighbour). */
51171
+ missed: number().int().nonnegative()
51172
+ });
51173
+ var RunningProposalEvidenceSchema = object({
51174
+ tier: RunningProposalTierSchema,
51175
+ spanMs: number().nonnegative(),
51176
+ from: number(),
51177
+ to: number(),
51178
+ points: number().int().nonnegative(),
51179
+ runsFound: number().int().nonnegative(),
51180
+ pausesFound: number().int().nonnegative(),
51181
+ longestPauseMs: number().nonnegative(),
51182
+ idleFloorW: number(),
51183
+ noiseCeilingW: number(),
51184
+ plateauW: number(),
51185
+ replay: RunningProposalReplaySchema
51186
+ });
51187
+ var RunningProposalInsufficientEvidenceSchema = object({
51188
+ spanMs: number().nonnegative(),
51189
+ points: number().int().nonnegative(),
51190
+ runsFound: number().int().nonnegative()
51191
+ });
51192
+ var RunningThresholdProposalSchema = discriminatedUnion("state", [object({
51193
+ state: literal("proposal"),
51194
+ transform: ThresholdTransformDraftSchema,
51195
+ evidence: RunningProposalEvidenceSchema,
51196
+ confidence: RunningProposalConfidenceSchema,
51197
+ /** Why the confidence is not higher; empty when nothing held it back. */
51198
+ notes: array(string())
51199
+ }), object({
51200
+ state: literal("insufficient"),
51201
+ reason: RunningProposalInsufficientReasonSchema,
51202
+ evidence: RunningProposalInsufficientEvidenceSchema,
51203
+ /** The catalog defaults, offered as what stands when nothing better is known. */
51204
+ fallback: ThresholdTransformDraftSchema
51205
+ })]);
51206
+ /**
50922
51207
  * The report of a one-shot "move this owner's plaintext secrets into the
50923
51208
  * keychain" run (D878). COUNTS only - never a value, never a ref.
50924
51209
  *
@@ -51215,6 +51500,14 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
51215
51500
  kind: "mutation",
51216
51501
  auth: "admin",
51217
51502
  access: "view"
51503
+ }), method(object({
51504
+ deviceId: number().int(),
51505
+ cap: string().min(1),
51506
+ fieldPath: string().min(1),
51507
+ deviceType: _enum(DeviceType).optional()
51508
+ }), RunningThresholdProposalSchema, {
51509
+ auth: "admin",
51510
+ access: "view"
51218
51511
  }), method(object({
51219
51512
  blockId: string().min(1),
51220
51513
  trace: AutomationRunTraceSchema.optional(),
@@ -55912,15 +56205,15 @@ var FanPresetCaptureResultSchema = object({
55912
56205
  items: array(FanCaptureItemSchema),
55913
56206
  omitted: array(FanCaptureOmissionSchema)
55914
56207
  });
55915
- var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
56208
+ var deviceInput$2 = object({ deviceId: number().int().nonnegative() });
55916
56209
  DeviceType.Fan;
55917
- method(deviceInput$1, array(FanPresetSchema), { auth: "protected" }), method(deviceInput$1.extend({ presets: array(FanPresetSchema).max(12) }), FanPresetsSetResultSchema, {
56210
+ method(deviceInput$2, array(FanPresetSchema), { auth: "protected" }), method(deviceInput$2.extend({ presets: array(FanPresetSchema).max(12) }), FanPresetsSetResultSchema, {
55918
56211
  kind: "mutation",
55919
56212
  auth: "admin"
55920
- }), method(deviceInput$1.extend({ presetId: string().min(1) }), FanPresetApplyResultSchema, {
56213
+ }), method(deviceInput$2.extend({ presetId: string().min(1) }), FanPresetApplyResultSchema, {
55921
56214
  kind: "mutation",
55922
56215
  auth: "protected"
55923
- }), method(deviceInput$1.extend({
56216
+ }), method(deviceInput$2.extend({
55924
56217
  fields: array(FanCaptureFieldSchema).optional(),
55925
56218
  steps: array(ActionStepSchema).max(20).default([])
55926
56219
  }), FanPresetCaptureResultSchema, { auth: "protected" });
@@ -59214,214 +59507,6 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
59214
59507
  ]);
59215
59508
  method(_void(), array(LoginMethodContributionSchema).readonly());
59216
59509
  /**
59217
- * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59218
- * Apple TV, Spotify, Roku, generic OTT receivers, …) on
59219
- * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
59220
- * surface — those use `DeviceType.Camera` + the broker pipeline.
59221
- *
59222
- * The cap declares a wide method surface; not every backend supports
59223
- * every method. Drivers signal sub-capability via the
59224
- * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
59225
- * corresponding method) so the UI gates buttons without a slice
59226
- * fetch — same pattern as `PanTiltZoom` for cameras.
59227
- */
59228
- var MediaPlayerStateSchema = _enum([
59229
- "off",
59230
- "on",
59231
- "idle",
59232
- "playing",
59233
- "paused",
59234
- "buffering",
59235
- "standby"
59236
- ]);
59237
- var MediaPlayerRepeatSchema = _enum([
59238
- "off",
59239
- "all",
59240
- "one"
59241
- ]);
59242
- var MediaInfoSchema = object({
59243
- /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
59244
- * `podcast`, …). */
59245
- type: string(),
59246
- /** Human-readable title. */
59247
- title: string(),
59248
- /** Optional artist / channel / station label. */
59249
- artist: string().optional(),
59250
- /** Optional album / season / show name. */
59251
- album: string().optional(),
59252
- /** Optional cover-art / thumbnail URL. */
59253
- imageUrl: string().optional()
59254
- });
59255
- /**
59256
- * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
59257
- * the device said so. `assumed`: the driver has no feedback (infrared) and
59258
- * tracks what it last SENT; it moves only after a send was accepted, and a
59259
- * human at the real remote makes it wrong. A UI shows an assumed value as a
59260
- * guess, never as a reading.
59261
- */
59262
- var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
59263
- /** The fields of a media-player status a driver can only guess. */
59264
- var MediaPlayerAssumedFieldSchema = _enum([
59265
- "state",
59266
- "volumeLevel",
59267
- "isMuted",
59268
- "source"
59269
- ]);
59270
- var MediaPlayerStatusSchema = object({
59271
- /** Playback lifecycle state. */
59272
- state: MediaPlayerStateSchema,
59273
- /**
59274
- * Whether the state fields are readings or the driver's own bookkeeping.
59275
- * A slice written before this field existed parses as `reported`.
59276
- */
59277
- stateSource: MediaPlayerStateSourceSchema.default("reported"),
59278
- /**
59279
- * Which fields are the driver's own guess. `stateSource` is `assumed` when
59280
- * this is not empty; a field not listed here is a reading even then (power
59281
- * from a running-state source, mute guessed from the last send).
59282
- */
59283
- assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
59284
- /** Volume as 0..100 inclusive. Null when the device has no volume
59285
- * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
59286
- volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59287
- /** Mute toggle distinct from volume=0. Null when no mute surface.
59288
- * Pair with `DeviceFeature.MediaPlayerMute`. */
59289
- isMuted: boolean().nullable(),
59290
- /** Active source / input. Empty when no source surface. */
59291
- source: string(),
59292
- /** Selectable sources. Empty when no source surface.
59293
- * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
59294
- availableSources: array(string()),
59295
- /** Currently-playing media info. Null when nothing is playing. */
59296
- currentMedia: MediaInfoSchema.nullable(),
59297
- /** Current playback position in ms. Null when not seekable or
59298
- * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
59299
- position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
59300
- /** Total duration of the current media in ms. Null when unknown
59301
- * (live stream) or nothing is playing. */
59302
- duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
59303
- /** Shuffle toggle. Null when no shuffle surface.
59304
- * Pair with `DeviceFeature.MediaPlayerShuffle`. */
59305
- shuffle: boolean().nullable(),
59306
- /** Repeat mode. Null when no repeat surface.
59307
- * Pair with `DeviceFeature.MediaPlayerRepeat`. */
59308
- repeat: MediaPlayerRepeatSchema.nullable(),
59309
- /** Ms epoch when the slice was last updated. */
59310
- lastChangedAt: number()
59311
- });
59312
- var mediaPlayerCapability = {
59313
- name: "media-player",
59314
- scope: "device",
59315
- deviceNative: true,
59316
- mode: "singleton",
59317
- deviceTypes: [DeviceType.MediaPlayer],
59318
- methods: {
59319
- play: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59320
- kind: "mutation",
59321
- auth: "protected"
59322
- }),
59323
- pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59324
- kind: "mutation",
59325
- auth: "protected"
59326
- }),
59327
- stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59328
- kind: "mutation",
59329
- auth: "protected"
59330
- }),
59331
- next: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59332
- kind: "mutation",
59333
- auth: "protected"
59334
- }),
59335
- previous: method(object({ deviceId: number().int().nonnegative() }), _void(), {
59336
- kind: "mutation",
59337
- auth: "protected"
59338
- }),
59339
- seek: method(object({
59340
- deviceId: number().int().nonnegative(),
59341
- position: number().int().nonnegative()
59342
- }), _void(), {
59343
- kind: "mutation",
59344
- auth: "protected"
59345
- }),
59346
- setVolume: method(object({
59347
- deviceId: number().int().nonnegative(),
59348
- volumeLevel: number().min(0).max(100)
59349
- }), _void(), {
59350
- kind: "mutation",
59351
- auth: "protected"
59352
- }),
59353
- setMute: method(object({
59354
- deviceId: number().int().nonnegative(),
59355
- muted: boolean()
59356
- }), _void(), {
59357
- kind: "mutation",
59358
- auth: "protected"
59359
- }),
59360
- setShuffle: method(object({
59361
- deviceId: number().int().nonnegative(),
59362
- shuffle: boolean()
59363
- }), _void(), {
59364
- kind: "mutation",
59365
- auth: "protected"
59366
- }),
59367
- setRepeat: method(object({
59368
- deviceId: number().int().nonnegative(),
59369
- repeat: MediaPlayerRepeatSchema
59370
- }), _void(), {
59371
- kind: "mutation",
59372
- auth: "protected"
59373
- }),
59374
- selectSource: method(object({
59375
- deviceId: number().int().nonnegative(),
59376
- source: string().min(1)
59377
- }), _void(), {
59378
- kind: "mutation",
59379
- auth: "protected"
59380
- }),
59381
- playMedia: method(object({
59382
- deviceId: number().int().nonnegative(),
59383
- /** Media identifier / URL. */
59384
- mediaId: string().min(1),
59385
- /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
59386
- * passes it through to the upstream service. */
59387
- mediaType: string().min(1)
59388
- }), _void(), {
59389
- kind: "mutation",
59390
- auth: "protected"
59391
- })
59392
- },
59393
- status: {
59394
- schema: MediaPlayerStatusSchema,
59395
- kind: "push"
59396
- },
59397
- /**
59398
- * Runtime-state slice — mirrored by the kernel. UI players read the
59399
- * full slice for live now-playing, volume, and progress updates
59400
- * without polling.
59401
- */
59402
- runtimeState: MediaPlayerStatusSchema,
59403
- /**
59404
- * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
59405
- *
59406
- * See `RuntimeStateDurability`. Enforced by
59407
- * `scripts/check-runtime-state-durability.ts`.
59408
- */
59409
- durability: "session",
59410
- /**
59411
- * History (D850): volume (a level an operator or an automation sets; the
59412
- * default 10 s floor folds a slider drag into its end value) and mute.
59413
- * `position` is not recorded: it moves continuously while playing.
59414
- */
59415
- history: { fields: {
59416
- volumeLevel: {
59417
- kind: "gauge",
59418
- unit: "%",
59419
- deadband: 1
59420
- },
59421
- isMuted: { kind: "boolean" }
59422
- } }
59423
- };
59424
- /**
59425
59510
  * mesh-network — collection cap for mesh-VPN providers.
59426
59511
  *
59427
59512
  * Different shape from `network-access` (public tunnels):
@@ -73505,6 +73590,14 @@ var powerMeterCapability = {
73505
73590
  deviceNative: true,
73506
73591
  mode: "singleton",
73507
73592
  deviceTypes: POWER_METER_DEVICE_TYPES,
73593
+ deviceConfig: { ui: {
73594
+ kind: "widget",
73595
+ widgetId: "host/power-meter-line",
73596
+ tab: "power",
73597
+ placement: "hero",
73598
+ label: "Power",
73599
+ order: 4
73600
+ } },
73508
73601
  methods: {},
73509
73602
  status: {
73510
73603
  schema: PowerMeterStatusSchema,
@@ -73564,6 +73657,117 @@ var powerMeterCapability = {
73564
73657
  volatileStateFields: ["lastFetchedAt"],
73565
73658
  customize: powerMeterCustomize
73566
73659
  };
73660
+ var PowerSourceRefusalReasonSchema = _enum([
73661
+ "no-power-source",
73662
+ "switch-missing",
73663
+ "switch-offline",
73664
+ "switch-unknown",
73665
+ "restart-in-progress",
73666
+ "switch-call-failed"
73667
+ ]);
73668
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
73669
+ accepted: literal(false),
73670
+ reason: PowerSourceRefusalReasonSchema,
73671
+ /** One line for the operator, naming the switch. */
73672
+ message: string()
73673
+ })]);
73674
+ var PowerSourceInfoSchema = object({
73675
+ /** False when the device has no power source linked; the rest is then empty. */
73676
+ linked: boolean(),
73677
+ switchDeviceId: number().nullable(),
73678
+ switchName: string().nullable(),
73679
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
73680
+ switchOn: boolean().nullable(),
73681
+ switchOnline: boolean().nullable(),
73682
+ restartInProgress: boolean(),
73683
+ offSeconds: number().int()
73684
+ });
73685
+ /** The composed slice: the switch state the link mirrors, plus the stored off time. */
73686
+ var PowerSourceStateSchema = object({
73687
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
73688
+ switchOn: boolean().nullable(),
73689
+ offSeconds: number().int(),
73690
+ lastFetchedAt: number()
73691
+ });
73692
+ var POWER_SOURCE_DEVICE_TYPES = [
73693
+ DeviceType.Gateway,
73694
+ DeviceType.Hub,
73695
+ DeviceType.Camera,
73696
+ DeviceType.Sensor,
73697
+ DeviceType.MediaPlayer,
73698
+ DeviceType.Vacuum,
73699
+ DeviceType.Generic,
73700
+ DeviceType.Washer,
73701
+ DeviceType.Dryer,
73702
+ DeviceType.Dishwasher,
73703
+ DeviceType.PetFountain,
73704
+ DeviceType.Fan,
73705
+ DeviceType.Humidifier,
73706
+ DeviceType.Climate,
73707
+ DeviceType.WaterHeater
73708
+ ];
73709
+ var powerSourceCustomize = {
73710
+ version: 1,
73711
+ targets: [{
73712
+ id: "switch",
73713
+ cardinality: "scalar",
73714
+ vocabulary: {
73715
+ cap: "power-source",
73716
+ stateField: "switchOn"
73717
+ },
73718
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73719
+ apply: "add",
73720
+ path: "switchOn",
73721
+ sources: [{
73722
+ kind: "switch",
73723
+ transforms: [{ kind: "identity" }]
73724
+ }],
73725
+ companions: [{
73726
+ kind: "constant",
73727
+ path: "offSeconds",
73728
+ value: 10,
73729
+ when: "add"
73730
+ }, {
73731
+ kind: "clock",
73732
+ path: "lastFetchedAt",
73733
+ when: "always"
73734
+ }],
73735
+ sourceReport: { status: "assignment-status" }
73736
+ }]
73737
+ };
73738
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
73739
+ var powerSourceCapability = {
73740
+ name: "power-source",
73741
+ scope: "device",
73742
+ mode: "singleton",
73743
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
73744
+ methods: {
73745
+ getStatus: systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }),
73746
+ powerOn: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
73747
+ kind: "mutation",
73748
+ auth: "admin"
73749
+ }),
73750
+ powerOff: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
73751
+ kind: "mutation",
73752
+ auth: "admin"
73753
+ }),
73754
+ forceRestart: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
73755
+ kind: "mutation",
73756
+ auth: "admin"
73757
+ })
73758
+ },
73759
+ runtimeState: PowerSourceStateSchema,
73760
+ customize: powerSourceCustomize,
73761
+ /**
73762
+ * Runtime-state durability: **session** — mirrored from the linked switch on
73763
+ * its next report; a restored value would outlive the reading it names.
73764
+ *
73765
+ * See `RuntimeStateDurability`. Enforced by
73766
+ * `scripts/check-runtime-state-durability.ts`.
73767
+ */
73768
+ durability: "session",
73769
+ history: "none"
73770
+ };
73567
73771
  /**
73568
73772
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
73569
73773
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -77098,7 +77302,13 @@ var RemoteMediaCommandSchema = _enum([
77098
77302
  "next",
77099
77303
  "previous",
77100
77304
  "setMute",
77101
- "selectSource"
77305
+ "selectSource",
77306
+ "turnOn",
77307
+ "turnOff",
77308
+ "volumeUp",
77309
+ "volumeDown",
77310
+ "channelUp",
77311
+ "channelDown"
77102
77312
  ]);
77103
77313
  /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
77104
77314
  var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
@@ -77119,7 +77329,7 @@ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.e
77119
77329
  }), RemoteSendResultSchema, {
77120
77330
  kind: "mutation",
77121
77331
  auth: "protected"
77122
- }), method(deviceInput.extend({
77332
+ }), method(deviceInput, MediaPlayerStatusSchema.nullable(), { auth: "protected" }), method(deviceInput.extend({
77123
77333
  command: RemoteMediaCommandSchema,
77124
77334
  muted: boolean().optional(),
77125
77335
  source: string().optional(),
@@ -79403,7 +79613,11 @@ listSignals: method(_void(), array(StreamSignalSchema).readonly()) }
79403
79613
  * `getSettingsUISchema()` surface.
79404
79614
  */
79405
79615
  var SwitchStatusSchema = object({
79406
- on: boolean().meta({ label: "On" }),
79616
+ /**
79617
+ * `null` = the device has never reported its state (a measurement that
79618
+ * has not happened is unknown, never `false`).
79619
+ */
79620
+ on: boolean().nullable().meta({ label: "On" }),
79407
79621
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
79408
79622
  lastChangedAt: number()
79409
79623
  });
@@ -79428,7 +79642,7 @@ var switchCapability = {
79428
79642
  }) },
79429
79643
  events: { onStateChanged: { data: object({
79430
79644
  deviceId: number(),
79431
- on: boolean(),
79645
+ on: boolean().nullable(),
79432
79646
  lastChangedAt: number()
79433
79647
  }) } },
79434
79648
  status: {
@@ -83031,6 +83245,7 @@ function buildEventKindDescriptor(kind, source) {
83031
83245
  }
83032
83246
  };
83033
83247
  }
83248
+ DeviceFeature.MediaPlayerPower, DeviceFeature.MediaPlayerVolumeStep, DeviceFeature.MediaPlayerChannelStep, DeviceFeature.MediaPlayerMute, DeviceFeature.MediaPlayerStop, DeviceFeature.MediaPlayerNext, DeviceFeature.MediaPlayerPrevious;
83034
83249
  var btn = (idSuffix, row, col, init) => ({
83035
83250
  idSuffix,
83036
83251
  row,
@@ -83157,6 +83372,34 @@ discriminatedUnion("kind", [object({
83157
83372
  kind: literal("pronto"),
83158
83373
  code: string()
83159
83374
  })]);
83375
+ /**
83376
+ * Propose a running threshold from a device's own power history (planning#405).
83377
+ *
83378
+ * Pure and deterministic: the same series gives the same answer. The series is
83379
+ * a HELD-VALUE step series — a point's value stands until the next point — which
83380
+ * is how device-history stores a gauge, so "time at a level" is exact, not a
83381
+ * count of samples.
83382
+ *
83383
+ * 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
83384
+ * near F. A device that is not near one level most of the time has no floor.
83385
+ * 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
83386
+ * 3. gaps between episodes split in two by the largest log-scale jump (>= 3x):
83387
+ * the short ones are pauses INSIDE a run (a soak), the long ones separate runs.
83388
+ * 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
83389
+ * grid a person would type; stop dwell covers the longest pause; start dwell
83390
+ * covers the longest standby blip above T.
83391
+ * 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
83392
+ * run must hold exactly one true interval and nothing may flap outside.
83393
+ */
83394
+ var SECOND_MS = 1e3;
83395
+ var MINUTE_MS$1 = 60 * SECOND_MS;
83396
+ 24 * (60 * MINUTE_MS$1);
83397
+ 10 * MINUTE_MS$1;
83398
+ 30 * SECOND_MS;
83399
+ 60 * SECOND_MS;
83400
+ 20 * MINUTE_MS$1;
83401
+ 10 * SECOND_MS;
83402
+ 10 * SECOND_MS;
83160
83403
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
83161
83404
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
83162
83405
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
@@ -85821,6 +86064,13 @@ Object.freeze({
85821
86064
  access: "create",
85822
86065
  role: "admin"
85823
86066
  },
86067
+ "coreBlocks.proposeRunningThreshold": {
86068
+ capName: "core-blocks",
86069
+ capScope: "system",
86070
+ addonId: null,
86071
+ access: "view",
86072
+ role: "admin"
86073
+ },
85824
86074
  "coreBlocks.reportAutomationRun": {
85825
86075
  capName: "core-blocks",
85826
86076
  capScope: "system",
@@ -88768,6 +89018,20 @@ Object.freeze({
88768
89018
  access: "view",
88769
89019
  role: "admin"
88770
89020
  },
89021
+ "mediaPlayer.channelDown": {
89022
+ capName: "media-player",
89023
+ capScope: "device",
89024
+ addonId: null,
89025
+ access: "create",
89026
+ role: "viewer"
89027
+ },
89028
+ "mediaPlayer.channelUp": {
89029
+ capName: "media-player",
89030
+ capScope: "device",
89031
+ addonId: null,
89032
+ access: "create",
89033
+ role: "viewer"
89034
+ },
88771
89035
  "mediaPlayer.getStatus": {
88772
89036
  capName: "media-player",
88773
89037
  capScope: "device",
@@ -88859,6 +89123,34 @@ Object.freeze({
88859
89123
  access: "create",
88860
89124
  role: "viewer"
88861
89125
  },
89126
+ "mediaPlayer.turnOff": {
89127
+ capName: "media-player",
89128
+ capScope: "device",
89129
+ addonId: null,
89130
+ access: "create",
89131
+ role: "viewer"
89132
+ },
89133
+ "mediaPlayer.turnOn": {
89134
+ capName: "media-player",
89135
+ capScope: "device",
89136
+ addonId: null,
89137
+ access: "create",
89138
+ role: "viewer"
89139
+ },
89140
+ "mediaPlayer.volumeDown": {
89141
+ capName: "media-player",
89142
+ capScope: "device",
89143
+ addonId: null,
89144
+ access: "create",
89145
+ role: "viewer"
89146
+ },
89147
+ "mediaPlayer.volumeUp": {
89148
+ capName: "media-player",
89149
+ capScope: "device",
89150
+ addonId: null,
89151
+ access: "create",
89152
+ role: "viewer"
89153
+ },
88862
89154
  "meshNetwork.getStatus": {
88863
89155
  capName: "mesh-network",
88864
89156
  capScope: "system",
@@ -92415,6 +92707,13 @@ Object.freeze({
92415
92707
  access: "create",
92416
92708
  role: "admin"
92417
92709
  },
92710
+ "remote.getAssumedStatus": {
92711
+ capName: "remote",
92712
+ capScope: "system",
92713
+ addonId: null,
92714
+ access: "view",
92715
+ role: "admin"
92716
+ },
92418
92717
  "remote.getConfig": {
92419
92718
  capName: "remote",
92420
92719
  capScope: "system",
@@ -95230,6 +95529,11 @@ Object.freeze({
95230
95529
  form: "single",
95231
95530
  optional: false
95232
95531
  }],
95532
+ "coreBlocks.proposeRunningThreshold": [{
95533
+ name: "deviceId",
95534
+ form: "single",
95535
+ optional: false
95536
+ }],
95233
95537
  "cover.close": [{
95234
95538
  name: "deviceId",
95235
95539
  form: "single",
@@ -96081,6 +96385,16 @@ Object.freeze({
96081
96385
  form: "single",
96082
96386
  optional: true
96083
96387
  }],
96388
+ "mediaPlayer.channelDown": [{
96389
+ name: "deviceId",
96390
+ form: "single",
96391
+ optional: false
96392
+ }],
96393
+ "mediaPlayer.channelUp": [{
96394
+ name: "deviceId",
96395
+ form: "single",
96396
+ optional: false
96397
+ }],
96084
96398
  "mediaPlayer.getStatus": [{
96085
96399
  name: "deviceId",
96086
96400
  form: "single",
@@ -96146,6 +96460,26 @@ Object.freeze({
96146
96460
  form: "single",
96147
96461
  optional: false
96148
96462
  }],
96463
+ "mediaPlayer.turnOff": [{
96464
+ name: "deviceId",
96465
+ form: "single",
96466
+ optional: false
96467
+ }],
96468
+ "mediaPlayer.turnOn": [{
96469
+ name: "deviceId",
96470
+ form: "single",
96471
+ optional: false
96472
+ }],
96473
+ "mediaPlayer.volumeDown": [{
96474
+ name: "deviceId",
96475
+ form: "single",
96476
+ optional: false
96477
+ }],
96478
+ "mediaPlayer.volumeUp": [{
96479
+ name: "deviceId",
96480
+ form: "single",
96481
+ optional: false
96482
+ }],
96149
96483
  "meter.getStatus": [{
96150
96484
  name: "deviceId",
96151
96485
  form: "single",
@@ -97311,6 +97645,11 @@ Object.freeze({
97311
97645
  form: "single",
97312
97646
  optional: true
97313
97647
  }],
97648
+ "remote.getAssumedStatus": [{
97649
+ name: "deviceId",
97650
+ form: "single",
97651
+ optional: false
97652
+ }],
97314
97653
  "remote.getConfig": [{
97315
97654
  name: "deviceId",
97316
97655
  form: "single",
@@ -97955,99 +98294,6 @@ var BucketAccumulator = class {
97955
98294
  return n;
97956
98295
  }
97957
98296
  };
97958
- /**
97959
- * A saved Customize assignment (D936). The schema is the type: callers use
97960
- * `z.infer`, they do not restate the shape.
97961
- */
97962
- var OverrideSourceSchema = object({
97963
- addonId: string().min(1),
97964
- stableId: string().min(1),
97965
- cap: string().min(1),
97966
- fieldPath: string().min(1)
97967
- });
97968
- var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
97969
- object({ kind: literal("identity") }),
97970
- object({ kind: literal("invert") }),
97971
- object({
97972
- kind: literal("threshold"),
97973
- comparison: _enum(["gte", "lte"]),
97974
- threshold: number(),
97975
- startDwellMs: number().nonnegative(),
97976
- stopDwellMs: number().nonnegative()
97977
- }),
97978
- object({
97979
- kind: literal("linear"),
97980
- scale: number(),
97981
- offset: number(),
97982
- clampMin: number().optional(),
97983
- clampMax: number().optional()
97984
- }),
97985
- object({
97986
- kind: literal("enum-map"),
97987
- mapping: record(string(), string().nullable())
97988
- }),
97989
- object({ kind: literal("number") })
97990
- ]);
97991
- var ScalarOverrideDraftSchema = object({
97992
- kind: literal("scalar"),
97993
- cap: string().min(1),
97994
- targetId: string().min(1),
97995
- source: OverrideSourceSchema,
97996
- transform: CustomizeTransformDraftSchema
97997
- });
97998
- var KeyedArrayOverrideDraftSchema = object({
97999
- kind: literal("keyedArray"),
98000
- cap: string().min(1),
98001
- targetId: string().min(1),
98002
- key: string().min(1),
98003
- label: string().min(1),
98004
- fieldPath: string().min(1),
98005
- source: OverrideSourceSchema,
98006
- transform: CustomizeTransformDraftSchema
98007
- });
98008
- var PulseOverrideDraftSchema = object({
98009
- kind: literal("pulse"),
98010
- cap: string().min(1),
98011
- targetId: string().min(1),
98012
- enabled: boolean(),
98013
- debounceMs: number().nonnegative(),
98014
- edges: array(_enum([
98015
- "rising",
98016
- "button",
98017
- "native-event"
98018
- ])).min(1).optional(),
98019
- sources: array(OverrideSourceSchema).min(1)
98020
- });
98021
- var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
98022
- "in-addition",
98023
- "confirm",
98024
- "replace"
98025
- ]).optional() });
98026
- discriminatedUnion("kind", [
98027
- ScalarOverrideDraftSchema,
98028
- KeyedArrayOverrideDraftSchema,
98029
- PulseOverrideDraftSchema,
98030
- object({
98031
- kind: literal("span"),
98032
- cap: string().min(1),
98033
- targetId: string().min(1),
98034
- timeoutMs: number().nonnegative(),
98035
- cooldownMs: number().nonnegative().optional(),
98036
- sources: array(SpanSourceDraftSchema)
98037
- })
98038
- ]);
98039
- object({
98040
- targetId: string().min(1),
98041
- configured: boolean(),
98042
- source: _enum(["native", "assigned"]),
98043
- state: _enum([
98044
- "active",
98045
- "stale",
98046
- "released",
98047
- "unavailable"
98048
- ]),
98049
- reason: string().nullable()
98050
- });
98051
98297
  var G711_SCALE_CORRECTION_DB = {
98052
98298
  PCMU: 20 * Math.log10(4),
98053
98299
  PCMA: 20 * Math.log10(8)