@camstack/addon-import-alexa 0.2.179 → 0.2.180

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.
package/dist/addon.js CHANGED
@@ -834,7 +834,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
834
834
  return EventCategory;
835
835
  }({});
836
836
  //#endregion
837
- //#region ../types/dist/device-type-CfHw_quR.mjs
837
+ //#region ../types/dist/device-type-D1fH5kaC.mjs
838
838
  /**
839
839
  import { errMsg } from '@camstack/types'
840
840
  * Extract a human-readable message from an unknown error value.
@@ -1065,6 +1065,12 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
1065
1065
  DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
1066
1066
  /** Media player exposes stop distinct from pause. */
1067
1067
  DeviceFeature["MediaPlayerStop"] = "media-player-stop";
1068
+ /** Media player exposes volume up / down in steps (an infrared TV has no level). */
1069
+ DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
1070
+ /** Media player exposes channel up / down in steps. */
1071
+ DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
1072
+ /** Media player exposes power on / off. */
1073
+ DeviceFeature["MediaPlayerPower"] = "media-player-power";
1068
1074
  /** Alarm panel requires a PIN code on arm/disarm. */
1069
1075
  DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
1070
1076
  /** Presence device carries GPS coordinates (lat/lng/accuracy) in
@@ -6038,7 +6044,7 @@ function number(params) {
6038
6044
  return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
6039
6045
  }
6040
6046
  //#endregion
6041
- //#region ../types/dist/sleep-hmSP-eJt.mjs
6047
+ //#region ../types/dist/sleep-BKClVk0K.mjs
6042
6048
  /**
6043
6049
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6044
6050
  * window to float samples (D455).
@@ -6117,6 +6123,22 @@ function buildAlawTable() {
6117
6123
  }
6118
6124
  buildUlawTable();
6119
6125
  buildAlawTable();
6126
+ /**
6127
+ * An addon whose own migrations did not apply refuses to initialise (D987). The error is typed
6128
+ * so a runner hosting several addons can tell "this addon is blocked" from a crash and keep its
6129
+ * co-located siblings running. Recognised by NAME and shape, never `instanceof`: a forked addon
6130
+ * bundles its own copy of this module, so the class the runner sees is not the one that threw.
6131
+ */
6132
+ var MIGRATIONS_BLOCKED_ERROR_NAME = "AddonMigrationsBlockedError";
6133
+ var AddonMigrationsBlockedError = class extends Error {
6134
+ /** The ledger ids that did not apply and block the owner. */
6135
+ migrationIds;
6136
+ constructor(migrationIds) {
6137
+ super(`migration(s) ${migrationIds.join(", ")} did not apply and block this addon — fix or retry them (migrations.retry), then restart it`);
6138
+ this.name = MIGRATIONS_BLOCKED_ERROR_NAME;
6139
+ this.migrationIds = migrationIds;
6140
+ }
6141
+ };
6120
6142
  /** Is this field's stored value a credential? */
6121
6143
  function isSecretConfigField(field) {
6122
6144
  if (field.type === "password") return true;
@@ -7770,7 +7792,7 @@ var BaseAddon = class {
7770
7792
  startMigration: (input) => api.startMigration.mutate(input),
7771
7793
  finishMigration: (input) => api.finishMigration.mutate(input)
7772
7794
  }, migrations, this.ctx.logger);
7773
- if (report.blockOwner.length > 0) throw new Error(`migration(s) ${report.blockOwner.join(", ")} did not apply and block this addon — fix or retry them (migrations.retry), then restart it`);
7795
+ if (report.blockOwner.length > 0) throw new AddonMigrationsBlockedError(report.blockOwner);
7774
7796
  return report;
7775
7797
  }
7776
7798
  /**
@@ -11766,7 +11788,7 @@ object({
11766
11788
  params: record(string(), union([string(), number$1()])).optional()
11767
11789
  });
11768
11790
  //#endregion
11769
- //#region ../types/dist/composition-Dh3RfMx5.mjs
11791
+ //#region ../types/dist/composition-BodkvOV0.mjs
11770
11792
  /**
11771
11793
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11772
11794
  *
@@ -12903,7 +12925,14 @@ var CompositionForwardCommandSchema = object({
12903
12925
  method: string().min(1),
12904
12926
  args: record(string().min(1), CompositionForwardArgSchema).optional()
12905
12927
  });
12906
- var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
12928
+ var CompositionCommandTargetSchema = discriminatedUnion("kind", [
12929
+ CompositionForwardCommandSchema,
12930
+ CompositionCodeSourceSchema,
12931
+ object({
12932
+ kind: literal("extension"),
12933
+ target: literal("remote")
12934
+ })
12935
+ ]);
12907
12936
  /** An item key inside an item-array cap (`consumables.items[<key>]`). */
12908
12937
  var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
12909
12938
  /**
@@ -19527,6 +19556,48 @@ var APPLIANCE_CAP_VOCABULARY = {
19527
19556
  scope: "device",
19528
19557
  noun: t("Media player", "Lettore multimediale"),
19529
19558
  actions: [
19559
+ {
19560
+ id: "media.turnOn",
19561
+ method: "turnOn",
19562
+ label: t("Turn on", "Accendi"),
19563
+ phrase: t("Turn on {device}", "Accendi {device}"),
19564
+ icon: "power"
19565
+ },
19566
+ {
19567
+ id: "media.turnOff",
19568
+ method: "turnOff",
19569
+ label: t("Turn off", "Spegni"),
19570
+ phrase: t("Turn off {device}", "Spegni {device}"),
19571
+ icon: "power"
19572
+ },
19573
+ {
19574
+ id: "media.volumeUp",
19575
+ method: "volumeUp",
19576
+ label: t("Volume up", "Alza il volume"),
19577
+ phrase: t("Raise the volume of {device}", "Alza il volume di {device}"),
19578
+ icon: "volume-2"
19579
+ },
19580
+ {
19581
+ id: "media.volumeDown",
19582
+ method: "volumeDown",
19583
+ label: t("Volume down", "Abbassa il volume"),
19584
+ phrase: t("Lower the volume of {device}", "Abbassa il volume di {device}"),
19585
+ icon: "volume-2"
19586
+ },
19587
+ {
19588
+ id: "media.channelUp",
19589
+ method: "channelUp",
19590
+ label: t("Channel up", "Canale successivo"),
19591
+ phrase: t("Go to the next channel on {device}", "Passa al canale successivo su {device}"),
19592
+ icon: "skip-forward"
19593
+ },
19594
+ {
19595
+ id: "media.channelDown",
19596
+ method: "channelDown",
19597
+ label: t("Channel down", "Canale precedente"),
19598
+ phrase: t("Go to the previous channel on {device}", "Torna al canale precedente su {device}"),
19599
+ icon: "skip-back"
19600
+ },
19530
19601
  {
19531
19602
  id: "media.play",
19532
19603
  method: "play",
@@ -49154,6 +49225,244 @@ var controlCapability = {
49154
49225
  */
49155
49226
  history: "none"
49156
49227
  };
49228
+ /**
49229
+ * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
49230
+ * Apple TV, Spotify, Roku, generic OTT receivers, …) on
49231
+ * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
49232
+ * surface — those use `DeviceType.Camera` + the broker pipeline.
49233
+ *
49234
+ * The cap declares a wide method surface; not every backend supports
49235
+ * every method. Drivers signal sub-capability via the
49236
+ * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
49237
+ * corresponding method) so the UI gates buttons without a slice
49238
+ * fetch — same pattern as `PanTiltZoom` for cameras.
49239
+ */
49240
+ var MediaPlayerStateSchema = _enum([
49241
+ "off",
49242
+ "on",
49243
+ "idle",
49244
+ "playing",
49245
+ "paused",
49246
+ "buffering",
49247
+ "standby"
49248
+ ]);
49249
+ var MediaPlayerRepeatSchema = _enum([
49250
+ "off",
49251
+ "all",
49252
+ "one"
49253
+ ]);
49254
+ var MediaInfoSchema = object({
49255
+ /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
49256
+ * `podcast`, …). */
49257
+ type: string(),
49258
+ /** Human-readable title. */
49259
+ title: string(),
49260
+ /** Optional artist / channel / station label. */
49261
+ artist: string().optional(),
49262
+ /** Optional album / season / show name. */
49263
+ album: string().optional(),
49264
+ /** Optional cover-art / thumbnail URL. */
49265
+ imageUrl: string().optional()
49266
+ });
49267
+ /**
49268
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
49269
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
49270
+ * tracks what it last SENT; it moves only after a send was accepted, and a
49271
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
49272
+ * guess, never as a reading.
49273
+ */
49274
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
49275
+ /** The fields of a media-player status a driver can only guess. */
49276
+ var MediaPlayerAssumedFieldSchema = _enum([
49277
+ "state",
49278
+ "volumeLevel",
49279
+ "isMuted",
49280
+ "source"
49281
+ ]);
49282
+ var MediaPlayerStatusSchema = object({
49283
+ /** Playback lifecycle state. */
49284
+ state: MediaPlayerStateSchema,
49285
+ /**
49286
+ * Whether the state fields are readings or the driver's own bookkeeping.
49287
+ * A slice written before this field existed parses as `reported`.
49288
+ */
49289
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
49290
+ /**
49291
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
49292
+ * this is not empty; a field not listed here is a reading even then (power
49293
+ * from a running-state source, mute guessed from the last send).
49294
+ */
49295
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
49296
+ /** Volume as 0..100 inclusive. Null when the device has no volume
49297
+ * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
49298
+ volumeLevel: number$1().min(0).max(100).nullable().meta(readingMeta("percentage")),
49299
+ /** Mute toggle distinct from volume=0. Null when no mute surface.
49300
+ * Pair with `DeviceFeature.MediaPlayerMute`. */
49301
+ isMuted: boolean().nullable(),
49302
+ /** Active source / input. Empty when no source surface. */
49303
+ source: string(),
49304
+ /** Selectable sources. Empty when no source surface.
49305
+ * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
49306
+ availableSources: array(string()),
49307
+ /** Currently-playing media info. Null when nothing is playing. */
49308
+ currentMedia: MediaInfoSchema.nullable(),
49309
+ /** Current playback position in ms. Null when not seekable or
49310
+ * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
49311
+ position: number$1().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
49312
+ /** Total duration of the current media in ms. Null when unknown
49313
+ * (live stream) or nothing is playing. */
49314
+ duration: number$1().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
49315
+ /** Shuffle toggle. Null when no shuffle surface.
49316
+ * Pair with `DeviceFeature.MediaPlayerShuffle`. */
49317
+ shuffle: boolean().nullable(),
49318
+ /** Repeat mode. Null when no repeat surface.
49319
+ * Pair with `DeviceFeature.MediaPlayerRepeat`. */
49320
+ repeat: MediaPlayerRepeatSchema.nullable(),
49321
+ /** Ms epoch when the slice was last updated. */
49322
+ lastChangedAt: number$1()
49323
+ });
49324
+ var stepInput = object({
49325
+ deviceId: number$1().int().nonnegative(),
49326
+ /** How many presses: the caller's count (Alexa `volumeSteps`, `channelCount`). */
49327
+ steps: number$1().int().min(1).max(50).default(1)
49328
+ });
49329
+ var deviceOnly = object({ deviceId: number$1().int().nonnegative() });
49330
+ var mediaPlayerCapability = {
49331
+ name: "media-player",
49332
+ scope: "device",
49333
+ deviceNative: true,
49334
+ mode: "singleton",
49335
+ deviceTypes: [DeviceType.MediaPlayer],
49336
+ methods: {
49337
+ turnOn: method(deviceOnly, _void(), {
49338
+ kind: "mutation",
49339
+ auth: "protected"
49340
+ }),
49341
+ turnOff: method(deviceOnly, _void(), {
49342
+ kind: "mutation",
49343
+ auth: "protected"
49344
+ }),
49345
+ volumeUp: method(stepInput, _void(), {
49346
+ kind: "mutation",
49347
+ auth: "protected"
49348
+ }),
49349
+ volumeDown: method(stepInput, _void(), {
49350
+ kind: "mutation",
49351
+ auth: "protected"
49352
+ }),
49353
+ channelUp: method(stepInput, _void(), {
49354
+ kind: "mutation",
49355
+ auth: "protected"
49356
+ }),
49357
+ channelDown: method(stepInput, _void(), {
49358
+ kind: "mutation",
49359
+ auth: "protected"
49360
+ }),
49361
+ play: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
49362
+ kind: "mutation",
49363
+ auth: "protected"
49364
+ }),
49365
+ pause: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
49366
+ kind: "mutation",
49367
+ auth: "protected"
49368
+ }),
49369
+ stop: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
49370
+ kind: "mutation",
49371
+ auth: "protected"
49372
+ }),
49373
+ next: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
49374
+ kind: "mutation",
49375
+ auth: "protected"
49376
+ }),
49377
+ previous: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
49378
+ kind: "mutation",
49379
+ auth: "protected"
49380
+ }),
49381
+ seek: method(object({
49382
+ deviceId: number$1().int().nonnegative(),
49383
+ position: number$1().int().nonnegative()
49384
+ }), _void(), {
49385
+ kind: "mutation",
49386
+ auth: "protected"
49387
+ }),
49388
+ setVolume: method(object({
49389
+ deviceId: number$1().int().nonnegative(),
49390
+ volumeLevel: number$1().min(0).max(100)
49391
+ }), _void(), {
49392
+ kind: "mutation",
49393
+ auth: "protected"
49394
+ }),
49395
+ setMute: method(object({
49396
+ deviceId: number$1().int().nonnegative(),
49397
+ muted: boolean()
49398
+ }), _void(), {
49399
+ kind: "mutation",
49400
+ auth: "protected"
49401
+ }),
49402
+ setShuffle: method(object({
49403
+ deviceId: number$1().int().nonnegative(),
49404
+ shuffle: boolean()
49405
+ }), _void(), {
49406
+ kind: "mutation",
49407
+ auth: "protected"
49408
+ }),
49409
+ setRepeat: method(object({
49410
+ deviceId: number$1().int().nonnegative(),
49411
+ repeat: MediaPlayerRepeatSchema
49412
+ }), _void(), {
49413
+ kind: "mutation",
49414
+ auth: "protected"
49415
+ }),
49416
+ selectSource: method(object({
49417
+ deviceId: number$1().int().nonnegative(),
49418
+ source: string().min(1)
49419
+ }), _void(), {
49420
+ kind: "mutation",
49421
+ auth: "protected"
49422
+ }),
49423
+ playMedia: method(object({
49424
+ deviceId: number$1().int().nonnegative(),
49425
+ /** Media identifier / URL. */
49426
+ mediaId: string().min(1),
49427
+ /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
49428
+ * passes it through to the upstream service. */
49429
+ mediaType: string().min(1)
49430
+ }), _void(), {
49431
+ kind: "mutation",
49432
+ auth: "protected"
49433
+ })
49434
+ },
49435
+ status: {
49436
+ schema: MediaPlayerStatusSchema,
49437
+ kind: "push"
49438
+ },
49439
+ /**
49440
+ * Runtime-state slice — mirrored by the kernel. UI players read the
49441
+ * full slice for live now-playing, volume, and progress updates
49442
+ * without polling.
49443
+ */
49444
+ runtimeState: MediaPlayerStatusSchema,
49445
+ /**
49446
+ * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
49447
+ *
49448
+ * See `RuntimeStateDurability`. Enforced by
49449
+ * `scripts/check-runtime-state-durability.ts`.
49450
+ */
49451
+ durability: "session",
49452
+ /**
49453
+ * History (D850): volume (a level an operator or an automation sets; the
49454
+ * default 10 s floor folds a slider drag into its end value) and mute.
49455
+ * `position` is not recorded: it moves continuously while playing.
49456
+ */
49457
+ history: { fields: {
49458
+ volumeLevel: {
49459
+ kind: "gauge",
49460
+ unit: "%",
49461
+ deadband: 1
49462
+ },
49463
+ isMuted: { kind: "boolean" }
49464
+ } }
49465
+ };
49157
49466
  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;
49158
49467
  var NUMBER = {
49159
49468
  kind: "fixed",
@@ -57847,214 +58156,6 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
57847
58156
  ]);
57848
58157
  method(_void(), array(LoginMethodContributionSchema).readonly());
57849
58158
  /**
57850
- * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
57851
- * Apple TV, Spotify, Roku, generic OTT receivers, …) on
57852
- * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
57853
- * surface — those use `DeviceType.Camera` + the broker pipeline.
57854
- *
57855
- * The cap declares a wide method surface; not every backend supports
57856
- * every method. Drivers signal sub-capability via the
57857
- * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
57858
- * corresponding method) so the UI gates buttons without a slice
57859
- * fetch — same pattern as `PanTiltZoom` for cameras.
57860
- */
57861
- var MediaPlayerStateSchema = _enum([
57862
- "off",
57863
- "on",
57864
- "idle",
57865
- "playing",
57866
- "paused",
57867
- "buffering",
57868
- "standby"
57869
- ]);
57870
- var MediaPlayerRepeatSchema = _enum([
57871
- "off",
57872
- "all",
57873
- "one"
57874
- ]);
57875
- var MediaInfoSchema = object({
57876
- /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
57877
- * `podcast`, …). */
57878
- type: string(),
57879
- /** Human-readable title. */
57880
- title: string(),
57881
- /** Optional artist / channel / station label. */
57882
- artist: string().optional(),
57883
- /** Optional album / season / show name. */
57884
- album: string().optional(),
57885
- /** Optional cover-art / thumbnail URL. */
57886
- imageUrl: string().optional()
57887
- });
57888
- /**
57889
- * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
57890
- * the device said so. `assumed`: the driver has no feedback (infrared) and
57891
- * tracks what it last SENT; it moves only after a send was accepted, and a
57892
- * human at the real remote makes it wrong. A UI shows an assumed value as a
57893
- * guess, never as a reading.
57894
- */
57895
- var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
57896
- /** The fields of a media-player status a driver can only guess. */
57897
- var MediaPlayerAssumedFieldSchema = _enum([
57898
- "state",
57899
- "volumeLevel",
57900
- "isMuted",
57901
- "source"
57902
- ]);
57903
- var MediaPlayerStatusSchema = object({
57904
- /** Playback lifecycle state. */
57905
- state: MediaPlayerStateSchema,
57906
- /**
57907
- * Whether the state fields are readings or the driver's own bookkeeping.
57908
- * A slice written before this field existed parses as `reported`.
57909
- */
57910
- stateSource: MediaPlayerStateSourceSchema.default("reported"),
57911
- /**
57912
- * Which fields are the driver's own guess. `stateSource` is `assumed` when
57913
- * this is not empty; a field not listed here is a reading even then (power
57914
- * from a running-state source, mute guessed from the last send).
57915
- */
57916
- assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
57917
- /** Volume as 0..100 inclusive. Null when the device has no volume
57918
- * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
57919
- volumeLevel: number$1().min(0).max(100).nullable().meta(readingMeta("percentage")),
57920
- /** Mute toggle distinct from volume=0. Null when no mute surface.
57921
- * Pair with `DeviceFeature.MediaPlayerMute`. */
57922
- isMuted: boolean().nullable(),
57923
- /** Active source / input. Empty when no source surface. */
57924
- source: string(),
57925
- /** Selectable sources. Empty when no source surface.
57926
- * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
57927
- availableSources: array(string()),
57928
- /** Currently-playing media info. Null when nothing is playing. */
57929
- currentMedia: MediaInfoSchema.nullable(),
57930
- /** Current playback position in ms. Null when not seekable or
57931
- * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
57932
- position: number$1().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
57933
- /** Total duration of the current media in ms. Null when unknown
57934
- * (live stream) or nothing is playing. */
57935
- duration: number$1().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
57936
- /** Shuffle toggle. Null when no shuffle surface.
57937
- * Pair with `DeviceFeature.MediaPlayerShuffle`. */
57938
- shuffle: boolean().nullable(),
57939
- /** Repeat mode. Null when no repeat surface.
57940
- * Pair with `DeviceFeature.MediaPlayerRepeat`. */
57941
- repeat: MediaPlayerRepeatSchema.nullable(),
57942
- /** Ms epoch when the slice was last updated. */
57943
- lastChangedAt: number$1()
57944
- });
57945
- var mediaPlayerCapability = {
57946
- name: "media-player",
57947
- scope: "device",
57948
- deviceNative: true,
57949
- mode: "singleton",
57950
- deviceTypes: [DeviceType.MediaPlayer],
57951
- methods: {
57952
- play: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
57953
- kind: "mutation",
57954
- auth: "protected"
57955
- }),
57956
- pause: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
57957
- kind: "mutation",
57958
- auth: "protected"
57959
- }),
57960
- stop: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
57961
- kind: "mutation",
57962
- auth: "protected"
57963
- }),
57964
- next: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
57965
- kind: "mutation",
57966
- auth: "protected"
57967
- }),
57968
- previous: method(object({ deviceId: number$1().int().nonnegative() }), _void(), {
57969
- kind: "mutation",
57970
- auth: "protected"
57971
- }),
57972
- seek: method(object({
57973
- deviceId: number$1().int().nonnegative(),
57974
- position: number$1().int().nonnegative()
57975
- }), _void(), {
57976
- kind: "mutation",
57977
- auth: "protected"
57978
- }),
57979
- setVolume: method(object({
57980
- deviceId: number$1().int().nonnegative(),
57981
- volumeLevel: number$1().min(0).max(100)
57982
- }), _void(), {
57983
- kind: "mutation",
57984
- auth: "protected"
57985
- }),
57986
- setMute: method(object({
57987
- deviceId: number$1().int().nonnegative(),
57988
- muted: boolean()
57989
- }), _void(), {
57990
- kind: "mutation",
57991
- auth: "protected"
57992
- }),
57993
- setShuffle: method(object({
57994
- deviceId: number$1().int().nonnegative(),
57995
- shuffle: boolean()
57996
- }), _void(), {
57997
- kind: "mutation",
57998
- auth: "protected"
57999
- }),
58000
- setRepeat: method(object({
58001
- deviceId: number$1().int().nonnegative(),
58002
- repeat: MediaPlayerRepeatSchema
58003
- }), _void(), {
58004
- kind: "mutation",
58005
- auth: "protected"
58006
- }),
58007
- selectSource: method(object({
58008
- deviceId: number$1().int().nonnegative(),
58009
- source: string().min(1)
58010
- }), _void(), {
58011
- kind: "mutation",
58012
- auth: "protected"
58013
- }),
58014
- playMedia: method(object({
58015
- deviceId: number$1().int().nonnegative(),
58016
- /** Media identifier / URL. */
58017
- mediaId: string().min(1),
58018
- /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
58019
- * passes it through to the upstream service. */
58020
- mediaType: string().min(1)
58021
- }), _void(), {
58022
- kind: "mutation",
58023
- auth: "protected"
58024
- })
58025
- },
58026
- status: {
58027
- schema: MediaPlayerStatusSchema,
58028
- kind: "push"
58029
- },
58030
- /**
58031
- * Runtime-state slice — mirrored by the kernel. UI players read the
58032
- * full slice for live now-playing, volume, and progress updates
58033
- * without polling.
58034
- */
58035
- runtimeState: MediaPlayerStatusSchema,
58036
- /**
58037
- * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
58038
- *
58039
- * See `RuntimeStateDurability`. Enforced by
58040
- * `scripts/check-runtime-state-durability.ts`.
58041
- */
58042
- durability: "session",
58043
- /**
58044
- * History (D850): volume (a level an operator or an automation sets; the
58045
- * default 10 s floor folds a slider drag into its end value) and mute.
58046
- * `position` is not recorded: it moves continuously while playing.
58047
- */
58048
- history: { fields: {
58049
- volumeLevel: {
58050
- kind: "gauge",
58051
- unit: "%",
58052
- deadband: 1
58053
- },
58054
- isMuted: { kind: "boolean" }
58055
- } }
58056
- };
58057
- /**
58058
58159
  * mesh-network — collection cap for mesh-VPN providers.
58059
58160
  *
58060
58161
  * Different shape from `network-access` (public tunnels):
@@ -66813,6 +66914,21 @@ var NcTemplateVarKindSchema = _enum([
66813
66914
  "sound",
66814
66915
  "system"
66815
66916
  ]);
66917
+ /**
66918
+ * The default title/body a rule of one SITUATION is delivered with when the
66919
+ * operator wrote no template — served so an editor can pre-fill it (and the
66920
+ * operator can rebuild it from placeholders) instead of starting from a blank
66921
+ * box that, once saved, silently replaces it. `id` names the situation inside
66922
+ * a rule `kind`: `appliance-cycle` is a `sensor` rule whose device is an
66923
+ * appliance finishing a cycle. Texts are raw templates (`{{var}}` intact), in
66924
+ * the hub's current language and with its overrides applied.
66925
+ */
66926
+ var NcTemplateDefaultSchema = object({
66927
+ id: _enum(["appliance-cycle"]),
66928
+ kind: NcRuleKindSchema,
66929
+ title: string(),
66930
+ body: string()
66931
+ });
66816
66932
  /** Which producer renders a template: an ordinary rule, a timelapse, a digest. */
66817
66933
  var NcTemplateFamilySchema = _enum([
66818
66934
  "rule",
@@ -67668,7 +67784,11 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
67668
67784
  }), method(object({}), object({
67669
67785
  catalog: array(NcConditionDescriptorSchema),
67670
67786
  taxonomy: NcTaxonomySchema.optional()
67671
- })), method(object({}), object({ vars: array(NcTemplateVarDescriptorSchema) })), method(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, {
67787
+ })), method(object({}), object({
67788
+ vars: array(NcTemplateVarDescriptorSchema),
67789
+ /** Per-situation default texts; absent on a hub that predates them. */
67790
+ defaults: array(NcTemplateDefaultSchema)
67791
+ })), method(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, {
67672
67792
  kind: "mutation",
67673
67793
  access: "view"
67674
67794
  }), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" }), method(object({}), NcRuleLastRunsSchema, { auth: "admin" }), method(object({ artifactId: string().min(1) }), object({ url: string().nullable() }), { auth: "admin" }), method(object({}), object({ snoozes: array(NcSnoozeSchema) }), { caller: "required" }), method(object({ snooze: NcSnoozeInputSchema }), object({ snooze: NcSnoozeSchema }), {
@@ -73820,7 +73940,13 @@ var RemoteMediaCommandSchema = _enum([
73820
73940
  "next",
73821
73941
  "previous",
73822
73942
  "setMute",
73823
- "selectSource"
73943
+ "selectSource",
73944
+ "turnOn",
73945
+ "turnOff",
73946
+ "volumeUp",
73947
+ "volumeDown",
73948
+ "channelUp",
73949
+ "channelDown"
73824
73950
  ]);
73825
73951
  /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
73826
73952
  var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
@@ -73841,7 +73967,7 @@ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.e
73841
73967
  }), RemoteSendResultSchema, {
73842
73968
  kind: "mutation",
73843
73969
  auth: "protected"
73844
- }), method(deviceInput.extend({
73970
+ }), method(deviceInput, MediaPlayerStatusSchema.nullable(), { auth: "protected" }), method(deviceInput.extend({
73845
73971
  command: RemoteMediaCommandSchema,
73846
73972
  muted: boolean().optional(),
73847
73973
  source: string().optional(),
@@ -76087,7 +76213,11 @@ listSignals: method(_void(), array(StreamSignalSchema).readonly()) }
76087
76213
  * `getSettingsUISchema()` surface.
76088
76214
  */
76089
76215
  var SwitchStatusSchema = object({
76090
- on: boolean().meta({ label: "On" }),
76216
+ /**
76217
+ * `null` = the device has never reported its state (a measurement that
76218
+ * has not happened is unknown, never `false`).
76219
+ */
76220
+ on: boolean().nullable().meta({ label: "On" }),
76091
76221
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
76092
76222
  lastChangedAt: number$1()
76093
76223
  });
@@ -76112,7 +76242,7 @@ var switchCapability = {
76112
76242
  }) },
76113
76243
  events: { onStateChanged: { data: object({
76114
76244
  deviceId: number$1(),
76115
- on: boolean(),
76245
+ on: boolean().nullable(),
76116
76246
  lastChangedAt: number$1()
76117
76247
  }) } },
76118
76248
  status: {
@@ -79669,6 +79799,7 @@ function buildDescriptor(capName, kind) {
79669
79799
  * contributes one entry per bound cap present in this map.
79670
79800
  */
79671
79801
  var EVENT_KIND_BY_CAP = Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
79802
+ DeviceFeature.MediaPlayerPower, DeviceFeature.MediaPlayerVolumeStep, DeviceFeature.MediaPlayerChannelStep, DeviceFeature.MediaPlayerMute, DeviceFeature.MediaPlayerStop, DeviceFeature.MediaPlayerNext, DeviceFeature.MediaPlayerPrevious;
79672
79803
  var btn = (idSuffix, row, col, init) => ({
79673
79804
  idSuffix,
79674
79805
  row,
@@ -85847,6 +85978,20 @@ Object.freeze({
85847
85978
  access: "view",
85848
85979
  role: "admin"
85849
85980
  },
85981
+ "mediaPlayer.channelDown": {
85982
+ capName: "media-player",
85983
+ capScope: "device",
85984
+ addonId: null,
85985
+ access: "create",
85986
+ role: "viewer"
85987
+ },
85988
+ "mediaPlayer.channelUp": {
85989
+ capName: "media-player",
85990
+ capScope: "device",
85991
+ addonId: null,
85992
+ access: "create",
85993
+ role: "viewer"
85994
+ },
85850
85995
  "mediaPlayer.getStatus": {
85851
85996
  capName: "media-player",
85852
85997
  capScope: "device",
@@ -85938,6 +86083,34 @@ Object.freeze({
85938
86083
  access: "create",
85939
86084
  role: "viewer"
85940
86085
  },
86086
+ "mediaPlayer.turnOff": {
86087
+ capName: "media-player",
86088
+ capScope: "device",
86089
+ addonId: null,
86090
+ access: "create",
86091
+ role: "viewer"
86092
+ },
86093
+ "mediaPlayer.turnOn": {
86094
+ capName: "media-player",
86095
+ capScope: "device",
86096
+ addonId: null,
86097
+ access: "create",
86098
+ role: "viewer"
86099
+ },
86100
+ "mediaPlayer.volumeDown": {
86101
+ capName: "media-player",
86102
+ capScope: "device",
86103
+ addonId: null,
86104
+ access: "create",
86105
+ role: "viewer"
86106
+ },
86107
+ "mediaPlayer.volumeUp": {
86108
+ capName: "media-player",
86109
+ capScope: "device",
86110
+ addonId: null,
86111
+ access: "create",
86112
+ role: "viewer"
86113
+ },
85941
86114
  "meshNetwork.getStatus": {
85942
86115
  capName: "mesh-network",
85943
86116
  capScope: "system",
@@ -89494,6 +89667,13 @@ Object.freeze({
89494
89667
  access: "create",
89495
89668
  role: "admin"
89496
89669
  },
89670
+ "remote.getAssumedStatus": {
89671
+ capName: "remote",
89672
+ capScope: "system",
89673
+ addonId: null,
89674
+ access: "view",
89675
+ role: "admin"
89676
+ },
89497
89677
  "remote.getConfig": {
89498
89678
  capName: "remote",
89499
89679
  capScope: "system",
@@ -93160,6 +93340,16 @@ Object.freeze({
93160
93340
  form: "single",
93161
93341
  optional: true
93162
93342
  }],
93343
+ "mediaPlayer.channelDown": [{
93344
+ name: "deviceId",
93345
+ form: "single",
93346
+ optional: false
93347
+ }],
93348
+ "mediaPlayer.channelUp": [{
93349
+ name: "deviceId",
93350
+ form: "single",
93351
+ optional: false
93352
+ }],
93163
93353
  "mediaPlayer.getStatus": [{
93164
93354
  name: "deviceId",
93165
93355
  form: "single",
@@ -93225,6 +93415,26 @@ Object.freeze({
93225
93415
  form: "single",
93226
93416
  optional: false
93227
93417
  }],
93418
+ "mediaPlayer.turnOff": [{
93419
+ name: "deviceId",
93420
+ form: "single",
93421
+ optional: false
93422
+ }],
93423
+ "mediaPlayer.turnOn": [{
93424
+ name: "deviceId",
93425
+ form: "single",
93426
+ optional: false
93427
+ }],
93428
+ "mediaPlayer.volumeDown": [{
93429
+ name: "deviceId",
93430
+ form: "single",
93431
+ optional: false
93432
+ }],
93433
+ "mediaPlayer.volumeUp": [{
93434
+ name: "deviceId",
93435
+ form: "single",
93436
+ optional: false
93437
+ }],
93228
93438
  "meter.getStatus": [{
93229
93439
  name: "deviceId",
93230
93440
  form: "single",
@@ -94390,6 +94600,11 @@ Object.freeze({
94390
94600
  form: "single",
94391
94601
  optional: true
94392
94602
  }],
94603
+ "remote.getAssumedStatus": [{
94604
+ name: "deviceId",
94605
+ form: "single",
94606
+ optional: false
94607
+ }],
94393
94608
  "remote.getConfig": [{
94394
94609
  name: "deviceId",
94395
94610
  form: "single",
@@ -95852,6 +96067,7 @@ var STATE_SUMMARY_VARS = [
95852
96067
  [...RULE_TEXT],
95853
96068
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
95854
96069
  ([...RULE_TEXT], [...COMBINED_ALARM]),
96070
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
95855
96071
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
95856
96072
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
95857
96073
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -142369,6 +142585,12 @@ var AlexaEchoDevice = class extends BaseDevice {
142369
142585
  this.rereadSoon();
142370
142586
  },
142371
142587
  stop: async () => unsupported("stop"),
142588
+ turnOn: async () => unsupported("power"),
142589
+ turnOff: async () => unsupported("power"),
142590
+ volumeUp: async () => unsupported("volume steps"),
142591
+ volumeDown: async () => unsupported("volume steps"),
142592
+ channelUp: async () => unsupported("channel steps"),
142593
+ channelDown: async () => unsupported("channel steps"),
142372
142594
  seek: async () => unsupported("seek"),
142373
142595
  setMute: async () => unsupported("mute"),
142374
142596
  setShuffle: async () => unsupported("shuffle"),