@camstack/addon-provider-reolink 1.2.220 → 1.2.221

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
@@ -101481,7 +101481,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
101481
101481
  return EventCategory;
101482
101482
  }({});
101483
101483
  //#endregion
101484
- //#region ../types/dist/device-type-CfHw_quR.mjs
101484
+ //#region ../types/dist/device-type-D1fH5kaC.mjs
101485
101485
  /**
101486
101486
  import { errMsg } from '@camstack/types'
101487
101487
  * Extract a human-readable message from an unknown error value.
@@ -101712,6 +101712,12 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
101712
101712
  DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
101713
101713
  /** Media player exposes stop distinct from pause. */
101714
101714
  DeviceFeature["MediaPlayerStop"] = "media-player-stop";
101715
+ /** Media player exposes volume up / down in steps (an infrared TV has no level). */
101716
+ DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
101717
+ /** Media player exposes channel up / down in steps. */
101718
+ DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
101719
+ /** Media player exposes power on / off. */
101720
+ DeviceFeature["MediaPlayerPower"] = "media-player-power";
101715
101721
  /** Alarm panel requires a PIN code on arm/disarm. */
101716
101722
  DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
101717
101723
  /** Presence device carries GPS coordinates (lat/lng/accuracy) in
@@ -106538,7 +106544,7 @@ var ZodIssueCode = {
106538
106544
  var ZodFirstPartyTypeKind;
106539
106545
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
106540
106546
  //#endregion
106541
- //#region ../types/dist/sleep-hmSP-eJt.mjs
106547
+ //#region ../types/dist/sleep-BKClVk0K.mjs
106542
106548
  /**
106543
106549
  * The audio chunk plane's byte format, and the ONE expansion from a coded
106544
106550
  * window to float samples (D455).
@@ -106617,6 +106623,22 @@ function buildAlawTable() {
106617
106623
  }
106618
106624
  buildUlawTable();
106619
106625
  buildAlawTable();
106626
+ /**
106627
+ * An addon whose own migrations did not apply refuses to initialise (D987). The error is typed
106628
+ * so a runner hosting several addons can tell "this addon is blocked" from a crash and keep its
106629
+ * co-located siblings running. Recognised by NAME and shape, never `instanceof`: a forked addon
106630
+ * bundles its own copy of this module, so the class the runner sees is not the one that threw.
106631
+ */
106632
+ var MIGRATIONS_BLOCKED_ERROR_NAME = "AddonMigrationsBlockedError";
106633
+ var AddonMigrationsBlockedError = class extends Error {
106634
+ /** The ledger ids that did not apply and block the owner. */
106635
+ migrationIds;
106636
+ constructor(migrationIds) {
106637
+ super(`migration(s) ${migrationIds.join(", ")} did not apply and block this addon — fix or retry them (migrations.retry), then restart it`);
106638
+ this.name = MIGRATIONS_BLOCKED_ERROR_NAME;
106639
+ this.migrationIds = migrationIds;
106640
+ }
106641
+ };
106620
106642
  /** Is this field's stored value a credential? */
106621
106643
  function isSecretConfigField(field) {
106622
106644
  if (field.type === "password") return true;
@@ -108274,7 +108296,7 @@ var BaseAddon = class {
108274
108296
  startMigration: (input) => api.startMigration.mutate(input),
108275
108297
  finishMigration: (input) => api.finishMigration.mutate(input)
108276
108298
  }, migrations, this.ctx.logger);
108277
- 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`);
108299
+ if (report.blockOwner.length > 0) throw new AddonMigrationsBlockedError(report.blockOwner);
108278
108300
  return report;
108279
108301
  }
108280
108302
  /**
@@ -112229,7 +112251,7 @@ function sleep(ms) {
112229
112251
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
112230
112252
  }
112231
112253
  //#endregion
112232
- //#region ../types/dist/composition-Dh3RfMx5.mjs
112254
+ //#region ../types/dist/composition-BodkvOV0.mjs
112233
112255
  /**
112234
112256
  * The ffmpeg build every CamStack node downloads, per platform and arch.
112235
112257
  *
@@ -113366,7 +113388,14 @@ var CompositionForwardCommandSchema = object({
113366
113388
  method: string().min(1),
113367
113389
  args: record(string().min(1), CompositionForwardArgSchema).optional()
113368
113390
  });
113369
- var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
113391
+ var CompositionCommandTargetSchema = discriminatedUnion("kind", [
113392
+ CompositionForwardCommandSchema,
113393
+ CompositionCodeSourceSchema,
113394
+ object({
113395
+ kind: literal("extension"),
113396
+ target: literal("remote")
113397
+ })
113398
+ ]);
113370
113399
  /** An item key inside an item-array cap (`consumables.items[<key>]`). */
113371
113400
  var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
113372
113401
  /**
@@ -120476,6 +120505,48 @@ var APPLIANCE_CAP_VOCABULARY = {
120476
120505
  scope: "device",
120477
120506
  noun: t("Media player", "Lettore multimediale"),
120478
120507
  actions: [
120508
+ {
120509
+ id: "media.turnOn",
120510
+ method: "turnOn",
120511
+ label: t("Turn on", "Accendi"),
120512
+ phrase: t("Turn on {device}", "Accendi {device}"),
120513
+ icon: "power"
120514
+ },
120515
+ {
120516
+ id: "media.turnOff",
120517
+ method: "turnOff",
120518
+ label: t("Turn off", "Spegni"),
120519
+ phrase: t("Turn off {device}", "Spegni {device}"),
120520
+ icon: "power"
120521
+ },
120522
+ {
120523
+ id: "media.volumeUp",
120524
+ method: "volumeUp",
120525
+ label: t("Volume up", "Alza il volume"),
120526
+ phrase: t("Raise the volume of {device}", "Alza il volume di {device}"),
120527
+ icon: "volume-2"
120528
+ },
120529
+ {
120530
+ id: "media.volumeDown",
120531
+ method: "volumeDown",
120532
+ label: t("Volume down", "Abbassa il volume"),
120533
+ phrase: t("Lower the volume of {device}", "Abbassa il volume di {device}"),
120534
+ icon: "volume-2"
120535
+ },
120536
+ {
120537
+ id: "media.channelUp",
120538
+ method: "channelUp",
120539
+ label: t("Channel up", "Canale successivo"),
120540
+ phrase: t("Go to the next channel on {device}", "Passa al canale successivo su {device}"),
120541
+ icon: "skip-forward"
120542
+ },
120543
+ {
120544
+ id: "media.channelDown",
120545
+ method: "channelDown",
120546
+ label: t("Channel down", "Canale precedente"),
120547
+ phrase: t("Go to the previous channel on {device}", "Torna al canale precedente su {device}"),
120548
+ icon: "skip-back"
120549
+ },
120479
120550
  {
120480
120551
  id: "media.play",
120481
120552
  method: "play",
@@ -149996,6 +150067,244 @@ var controlCapability = {
149996
150067
  */
149997
150068
  history: "none"
149998
150069
  };
150070
+ /**
150071
+ * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
150072
+ * Apple TV, Spotify, Roku, generic OTT receivers, …) on
150073
+ * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
150074
+ * surface — those use `DeviceType.Camera` + the broker pipeline.
150075
+ *
150076
+ * The cap declares a wide method surface; not every backend supports
150077
+ * every method. Drivers signal sub-capability via the
150078
+ * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
150079
+ * corresponding method) so the UI gates buttons without a slice
150080
+ * fetch — same pattern as `PanTiltZoom` for cameras.
150081
+ */
150082
+ var MediaPlayerStateSchema = _enum([
150083
+ "off",
150084
+ "on",
150085
+ "idle",
150086
+ "playing",
150087
+ "paused",
150088
+ "buffering",
150089
+ "standby"
150090
+ ]);
150091
+ var MediaPlayerRepeatSchema = _enum([
150092
+ "off",
150093
+ "all",
150094
+ "one"
150095
+ ]);
150096
+ var MediaInfoSchema = object({
150097
+ /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
150098
+ * `podcast`, …). */
150099
+ type: string(),
150100
+ /** Human-readable title. */
150101
+ title: string(),
150102
+ /** Optional artist / channel / station label. */
150103
+ artist: string().optional(),
150104
+ /** Optional album / season / show name. */
150105
+ album: string().optional(),
150106
+ /** Optional cover-art / thumbnail URL. */
150107
+ imageUrl: string().optional()
150108
+ });
150109
+ /**
150110
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
150111
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
150112
+ * tracks what it last SENT; it moves only after a send was accepted, and a
150113
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
150114
+ * guess, never as a reading.
150115
+ */
150116
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
150117
+ /** The fields of a media-player status a driver can only guess. */
150118
+ var MediaPlayerAssumedFieldSchema = _enum([
150119
+ "state",
150120
+ "volumeLevel",
150121
+ "isMuted",
150122
+ "source"
150123
+ ]);
150124
+ var MediaPlayerStatusSchema = object({
150125
+ /** Playback lifecycle state. */
150126
+ state: MediaPlayerStateSchema,
150127
+ /**
150128
+ * Whether the state fields are readings or the driver's own bookkeeping.
150129
+ * A slice written before this field existed parses as `reported`.
150130
+ */
150131
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
150132
+ /**
150133
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
150134
+ * this is not empty; a field not listed here is a reading even then (power
150135
+ * from a running-state source, mute guessed from the last send).
150136
+ */
150137
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
150138
+ /** Volume as 0..100 inclusive. Null when the device has no volume
150139
+ * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
150140
+ volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
150141
+ /** Mute toggle distinct from volume=0. Null when no mute surface.
150142
+ * Pair with `DeviceFeature.MediaPlayerMute`. */
150143
+ isMuted: boolean().nullable(),
150144
+ /** Active source / input. Empty when no source surface. */
150145
+ source: string(),
150146
+ /** Selectable sources. Empty when no source surface.
150147
+ * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
150148
+ availableSources: array(string()),
150149
+ /** Currently-playing media info. Null when nothing is playing. */
150150
+ currentMedia: MediaInfoSchema.nullable(),
150151
+ /** Current playback position in ms. Null when not seekable or
150152
+ * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
150153
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
150154
+ /** Total duration of the current media in ms. Null when unknown
150155
+ * (live stream) or nothing is playing. */
150156
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
150157
+ /** Shuffle toggle. Null when no shuffle surface.
150158
+ * Pair with `DeviceFeature.MediaPlayerShuffle`. */
150159
+ shuffle: boolean().nullable(),
150160
+ /** Repeat mode. Null when no repeat surface.
150161
+ * Pair with `DeviceFeature.MediaPlayerRepeat`. */
150162
+ repeat: MediaPlayerRepeatSchema.nullable(),
150163
+ /** Ms epoch when the slice was last updated. */
150164
+ lastChangedAt: number()
150165
+ });
150166
+ var stepInput = object({
150167
+ deviceId: number().int().nonnegative(),
150168
+ /** How many presses: the caller's count (Alexa `volumeSteps`, `channelCount`). */
150169
+ steps: number().int().min(1).max(50).default(1)
150170
+ });
150171
+ var deviceOnly = object({ deviceId: number().int().nonnegative() });
150172
+ var mediaPlayerCapability = {
150173
+ name: "media-player",
150174
+ scope: "device",
150175
+ deviceNative: true,
150176
+ mode: "singleton",
150177
+ deviceTypes: [DeviceType.MediaPlayer],
150178
+ methods: {
150179
+ turnOn: method(deviceOnly, _void(), {
150180
+ kind: "mutation",
150181
+ auth: "protected"
150182
+ }),
150183
+ turnOff: method(deviceOnly, _void(), {
150184
+ kind: "mutation",
150185
+ auth: "protected"
150186
+ }),
150187
+ volumeUp: method(stepInput, _void(), {
150188
+ kind: "mutation",
150189
+ auth: "protected"
150190
+ }),
150191
+ volumeDown: method(stepInput, _void(), {
150192
+ kind: "mutation",
150193
+ auth: "protected"
150194
+ }),
150195
+ channelUp: method(stepInput, _void(), {
150196
+ kind: "mutation",
150197
+ auth: "protected"
150198
+ }),
150199
+ channelDown: method(stepInput, _void(), {
150200
+ kind: "mutation",
150201
+ auth: "protected"
150202
+ }),
150203
+ play: method(object({ deviceId: number().int().nonnegative() }), _void(), {
150204
+ kind: "mutation",
150205
+ auth: "protected"
150206
+ }),
150207
+ pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
150208
+ kind: "mutation",
150209
+ auth: "protected"
150210
+ }),
150211
+ stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
150212
+ kind: "mutation",
150213
+ auth: "protected"
150214
+ }),
150215
+ next: method(object({ deviceId: number().int().nonnegative() }), _void(), {
150216
+ kind: "mutation",
150217
+ auth: "protected"
150218
+ }),
150219
+ previous: method(object({ deviceId: number().int().nonnegative() }), _void(), {
150220
+ kind: "mutation",
150221
+ auth: "protected"
150222
+ }),
150223
+ seek: method(object({
150224
+ deviceId: number().int().nonnegative(),
150225
+ position: number().int().nonnegative()
150226
+ }), _void(), {
150227
+ kind: "mutation",
150228
+ auth: "protected"
150229
+ }),
150230
+ setVolume: method(object({
150231
+ deviceId: number().int().nonnegative(),
150232
+ volumeLevel: number().min(0).max(100)
150233
+ }), _void(), {
150234
+ kind: "mutation",
150235
+ auth: "protected"
150236
+ }),
150237
+ setMute: method(object({
150238
+ deviceId: number().int().nonnegative(),
150239
+ muted: boolean()
150240
+ }), _void(), {
150241
+ kind: "mutation",
150242
+ auth: "protected"
150243
+ }),
150244
+ setShuffle: method(object({
150245
+ deviceId: number().int().nonnegative(),
150246
+ shuffle: boolean()
150247
+ }), _void(), {
150248
+ kind: "mutation",
150249
+ auth: "protected"
150250
+ }),
150251
+ setRepeat: method(object({
150252
+ deviceId: number().int().nonnegative(),
150253
+ repeat: MediaPlayerRepeatSchema
150254
+ }), _void(), {
150255
+ kind: "mutation",
150256
+ auth: "protected"
150257
+ }),
150258
+ selectSource: method(object({
150259
+ deviceId: number().int().nonnegative(),
150260
+ source: string().min(1)
150261
+ }), _void(), {
150262
+ kind: "mutation",
150263
+ auth: "protected"
150264
+ }),
150265
+ playMedia: method(object({
150266
+ deviceId: number().int().nonnegative(),
150267
+ /** Media identifier / URL. */
150268
+ mediaId: string().min(1),
150269
+ /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
150270
+ * passes it through to the upstream service. */
150271
+ mediaType: string().min(1)
150272
+ }), _void(), {
150273
+ kind: "mutation",
150274
+ auth: "protected"
150275
+ })
150276
+ },
150277
+ status: {
150278
+ schema: MediaPlayerStatusSchema,
150279
+ kind: "push"
150280
+ },
150281
+ /**
150282
+ * Runtime-state slice — mirrored by the kernel. UI players read the
150283
+ * full slice for live now-playing, volume, and progress updates
150284
+ * without polling.
150285
+ */
150286
+ runtimeState: MediaPlayerStatusSchema,
150287
+ /**
150288
+ * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
150289
+ *
150290
+ * See `RuntimeStateDurability`. Enforced by
150291
+ * `scripts/check-runtime-state-durability.ts`.
150292
+ */
150293
+ durability: "session",
150294
+ /**
150295
+ * History (D850): volume (a level an operator or an automation sets; the
150296
+ * default 10 s floor folds a slider drag into its end value) and mute.
150297
+ * `position` is not recorded: it moves continuously while playing.
150298
+ */
150299
+ history: { fields: {
150300
+ volumeLevel: {
150301
+ kind: "gauge",
150302
+ unit: "%",
150303
+ deadband: 1
150304
+ },
150305
+ isMuted: { kind: "boolean" }
150306
+ } }
150307
+ };
149999
150308
  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;
150000
150309
  var NUMBER = {
150001
150310
  kind: "fixed",
@@ -158763,214 +159072,6 @@ var LoginMethodContributionSchema = discriminatedUnion("kind", [
158763
159072
  ]);
158764
159073
  method(_void(), array(LoginMethodContributionSchema).readonly());
158765
159074
  /**
158766
- * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
158767
- * Apple TV, Spotify, Roku, generic OTT receivers, …) on
158768
- * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
158769
- * surface — those use `DeviceType.Camera` + the broker pipeline.
158770
- *
158771
- * The cap declares a wide method surface; not every backend supports
158772
- * every method. Drivers signal sub-capability via the
158773
- * `DeviceFeature.MediaPlayerXxx` flags (paired one-to-one with the
158774
- * corresponding method) so the UI gates buttons without a slice
158775
- * fetch — same pattern as `PanTiltZoom` for cameras.
158776
- */
158777
- var MediaPlayerStateSchema = _enum([
158778
- "off",
158779
- "on",
158780
- "idle",
158781
- "playing",
158782
- "paused",
158783
- "buffering",
158784
- "standby"
158785
- ]);
158786
- var MediaPlayerRepeatSchema = _enum([
158787
- "off",
158788
- "all",
158789
- "one"
158790
- ]);
158791
- var MediaInfoSchema = object({
158792
- /** Free-form media kind (`music`, `tvshow`, `movie`, `app`, `channel`,
158793
- * `podcast`, …). */
158794
- type: string(),
158795
- /** Human-readable title. */
158796
- title: string(),
158797
- /** Optional artist / channel / station label. */
158798
- artist: string().optional(),
158799
- /** Optional album / season / show name. */
158800
- album: string().optional(),
158801
- /** Optional cover-art / thumbnail URL. */
158802
- imageUrl: string().optional()
158803
- });
158804
- /**
158805
- * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
158806
- * the device said so. `assumed`: the driver has no feedback (infrared) and
158807
- * tracks what it last SENT; it moves only after a send was accepted, and a
158808
- * human at the real remote makes it wrong. A UI shows an assumed value as a
158809
- * guess, never as a reading.
158810
- */
158811
- var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
158812
- /** The fields of a media-player status a driver can only guess. */
158813
- var MediaPlayerAssumedFieldSchema = _enum([
158814
- "state",
158815
- "volumeLevel",
158816
- "isMuted",
158817
- "source"
158818
- ]);
158819
- var MediaPlayerStatusSchema = object({
158820
- /** Playback lifecycle state. */
158821
- state: MediaPlayerStateSchema,
158822
- /**
158823
- * Whether the state fields are readings or the driver's own bookkeeping.
158824
- * A slice written before this field existed parses as `reported`.
158825
- */
158826
- stateSource: MediaPlayerStateSourceSchema.default("reported"),
158827
- /**
158828
- * Which fields are the driver's own guess. `stateSource` is `assumed` when
158829
- * this is not empty; a field not listed here is a reading even then (power
158830
- * from a running-state source, mute guessed from the last send).
158831
- */
158832
- assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
158833
- /** Volume as 0..100 inclusive. Null when the device has no volume
158834
- * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
158835
- volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
158836
- /** Mute toggle distinct from volume=0. Null when no mute surface.
158837
- * Pair with `DeviceFeature.MediaPlayerMute`. */
158838
- isMuted: boolean().nullable(),
158839
- /** Active source / input. Empty when no source surface. */
158840
- source: string(),
158841
- /** Selectable sources. Empty when no source surface.
158842
- * Pair with `DeviceFeature.MediaPlayerSelectSource`. */
158843
- availableSources: array(string()),
158844
- /** Currently-playing media info. Null when nothing is playing. */
158845
- currentMedia: MediaInfoSchema.nullable(),
158846
- /** Current playback position in ms. Null when not seekable or
158847
- * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
158848
- position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
158849
- /** Total duration of the current media in ms. Null when unknown
158850
- * (live stream) or nothing is playing. */
158851
- duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
158852
- /** Shuffle toggle. Null when no shuffle surface.
158853
- * Pair with `DeviceFeature.MediaPlayerShuffle`. */
158854
- shuffle: boolean().nullable(),
158855
- /** Repeat mode. Null when no repeat surface.
158856
- * Pair with `DeviceFeature.MediaPlayerRepeat`. */
158857
- repeat: MediaPlayerRepeatSchema.nullable(),
158858
- /** Ms epoch when the slice was last updated. */
158859
- lastChangedAt: number()
158860
- });
158861
- var mediaPlayerCapability = {
158862
- name: "media-player",
158863
- scope: "device",
158864
- deviceNative: true,
158865
- mode: "singleton",
158866
- deviceTypes: [DeviceType.MediaPlayer],
158867
- methods: {
158868
- play: method(object({ deviceId: number().int().nonnegative() }), _void(), {
158869
- kind: "mutation",
158870
- auth: "protected"
158871
- }),
158872
- pause: method(object({ deviceId: number().int().nonnegative() }), _void(), {
158873
- kind: "mutation",
158874
- auth: "protected"
158875
- }),
158876
- stop: method(object({ deviceId: number().int().nonnegative() }), _void(), {
158877
- kind: "mutation",
158878
- auth: "protected"
158879
- }),
158880
- next: method(object({ deviceId: number().int().nonnegative() }), _void(), {
158881
- kind: "mutation",
158882
- auth: "protected"
158883
- }),
158884
- previous: method(object({ deviceId: number().int().nonnegative() }), _void(), {
158885
- kind: "mutation",
158886
- auth: "protected"
158887
- }),
158888
- seek: method(object({
158889
- deviceId: number().int().nonnegative(),
158890
- position: number().int().nonnegative()
158891
- }), _void(), {
158892
- kind: "mutation",
158893
- auth: "protected"
158894
- }),
158895
- setVolume: method(object({
158896
- deviceId: number().int().nonnegative(),
158897
- volumeLevel: number().min(0).max(100)
158898
- }), _void(), {
158899
- kind: "mutation",
158900
- auth: "protected"
158901
- }),
158902
- setMute: method(object({
158903
- deviceId: number().int().nonnegative(),
158904
- muted: boolean()
158905
- }), _void(), {
158906
- kind: "mutation",
158907
- auth: "protected"
158908
- }),
158909
- setShuffle: method(object({
158910
- deviceId: number().int().nonnegative(),
158911
- shuffle: boolean()
158912
- }), _void(), {
158913
- kind: "mutation",
158914
- auth: "protected"
158915
- }),
158916
- setRepeat: method(object({
158917
- deviceId: number().int().nonnegative(),
158918
- repeat: MediaPlayerRepeatSchema
158919
- }), _void(), {
158920
- kind: "mutation",
158921
- auth: "protected"
158922
- }),
158923
- selectSource: method(object({
158924
- deviceId: number().int().nonnegative(),
158925
- source: string().min(1)
158926
- }), _void(), {
158927
- kind: "mutation",
158928
- auth: "protected"
158929
- }),
158930
- playMedia: method(object({
158931
- deviceId: number().int().nonnegative(),
158932
- /** Media identifier / URL. */
158933
- mediaId: string().min(1),
158934
- /** Media kind (`music`, `tvshow`, `movie`, `app`, …) — provider
158935
- * passes it through to the upstream service. */
158936
- mediaType: string().min(1)
158937
- }), _void(), {
158938
- kind: "mutation",
158939
- auth: "protected"
158940
- })
158941
- },
158942
- status: {
158943
- schema: MediaPlayerStatusSchema,
158944
- kind: "push"
158945
- },
158946
- /**
158947
- * Runtime-state slice — mirrored by the kernel. UI players read the
158948
- * full slice for live now-playing, volume, and progress updates
158949
- * without polling.
158950
- */
158951
- runtimeState: MediaPlayerStatusSchema,
158952
- /**
158953
- * Runtime-state durability: **session** — a restored transport position describes a playback that stopped when the hub did.
158954
- *
158955
- * See `RuntimeStateDurability`. Enforced by
158956
- * `scripts/check-runtime-state-durability.ts`.
158957
- */
158958
- durability: "session",
158959
- /**
158960
- * History (D850): volume (a level an operator or an automation sets; the
158961
- * default 10 s floor folds a slider drag into its end value) and mute.
158962
- * `position` is not recorded: it moves continuously while playing.
158963
- */
158964
- history: { fields: {
158965
- volumeLevel: {
158966
- kind: "gauge",
158967
- unit: "%",
158968
- deadband: 1
158969
- },
158970
- isMuted: { kind: "boolean" }
158971
- } }
158972
- };
158973
- /**
158974
159075
  * mesh-network — collection cap for mesh-VPN providers.
158975
159076
  *
158976
159077
  * Different shape from `network-access` (public tunnels):
@@ -167749,6 +167850,21 @@ var NcTemplateVarKindSchema = _enum([
167749
167850
  "sound",
167750
167851
  "system"
167751
167852
  ]);
167853
+ /**
167854
+ * The default title/body a rule of one SITUATION is delivered with when the
167855
+ * operator wrote no template — served so an editor can pre-fill it (and the
167856
+ * operator can rebuild it from placeholders) instead of starting from a blank
167857
+ * box that, once saved, silently replaces it. `id` names the situation inside
167858
+ * a rule `kind`: `appliance-cycle` is a `sensor` rule whose device is an
167859
+ * appliance finishing a cycle. Texts are raw templates (`{{var}}` intact), in
167860
+ * the hub's current language and with its overrides applied.
167861
+ */
167862
+ var NcTemplateDefaultSchema = object({
167863
+ id: _enum(["appliance-cycle"]),
167864
+ kind: NcRuleKindSchema,
167865
+ title: string(),
167866
+ body: string()
167867
+ });
167752
167868
  /** Which producer renders a template: an ordinary rule, a timelapse, a digest. */
167753
167869
  var NcTemplateFamilySchema = _enum([
167754
167870
  "rule",
@@ -168604,7 +168720,11 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
168604
168720
  }), method(object({}), object({
168605
168721
  catalog: array(NcConditionDescriptorSchema),
168606
168722
  taxonomy: NcTaxonomySchema.optional()
168607
- })), method(object({}), object({ vars: array(NcTemplateVarDescriptorSchema) })), method(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, {
168723
+ })), method(object({}), object({
168724
+ vars: array(NcTemplateVarDescriptorSchema),
168725
+ /** Per-situation default texts; absent on a hub that predates them. */
168726
+ defaults: array(NcTemplateDefaultSchema)
168727
+ })), method(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, {
168608
168728
  kind: "mutation",
168609
168729
  access: "view"
168610
168730
  }), 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 }), {
@@ -175362,7 +175482,13 @@ var RemoteMediaCommandSchema = _enum([
175362
175482
  "next",
175363
175483
  "previous",
175364
175484
  "setMute",
175365
- "selectSource"
175485
+ "selectSource",
175486
+ "turnOn",
175487
+ "turnOff",
175488
+ "volumeUp",
175489
+ "volumeDown",
175490
+ "channelUp",
175491
+ "channelDown"
175366
175492
  ]);
175367
175493
  /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
175368
175494
  var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
@@ -175383,7 +175509,7 @@ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.e
175383
175509
  }), RemoteSendResultSchema, {
175384
175510
  kind: "mutation",
175385
175511
  auth: "protected"
175386
- }), method(deviceInput.extend({
175512
+ }), method(deviceInput, MediaPlayerStatusSchema.nullable(), { auth: "protected" }), method(deviceInput.extend({
175387
175513
  command: RemoteMediaCommandSchema,
175388
175514
  muted: boolean().optional(),
175389
175515
  source: string().optional(),
@@ -177733,7 +177859,11 @@ listSignals: method(_void(), array(StreamSignalSchema).readonly()) }
177733
177859
  * `getSettingsUISchema()` surface.
177734
177860
  */
177735
177861
  var SwitchStatusSchema = object({
177736
- on: boolean().meta({ label: "On" }),
177862
+ /**
177863
+ * `null` = the device has never reported its state (a measurement that
177864
+ * has not happened is unknown, never `false`).
177865
+ */
177866
+ on: boolean().nullable().meta({ label: "On" }),
177737
177867
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
177738
177868
  lastChangedAt: number()
177739
177869
  });
@@ -177758,7 +177888,7 @@ var switchCapability = {
177758
177888
  }) },
177759
177889
  events: { onStateChanged: { data: object({
177760
177890
  deviceId: number(),
177761
- on: boolean(),
177891
+ on: boolean().nullable(),
177762
177892
  lastChangedAt: number()
177763
177893
  }) } },
177764
177894
  status: {
@@ -181770,6 +181900,7 @@ function buildStreamParamsConfigSchema(options, status) {
181770
181900
  if (sections.length === 0) return null;
181771
181901
  return { sections };
181772
181902
  }
181903
+ DeviceFeature.MediaPlayerPower, DeviceFeature.MediaPlayerVolumeStep, DeviceFeature.MediaPlayerChannelStep, DeviceFeature.MediaPlayerMute, DeviceFeature.MediaPlayerStop, DeviceFeature.MediaPlayerNext, DeviceFeature.MediaPlayerPrevious;
181773
181904
  var btn = (idSuffix, row, col, init) => ({
181774
181905
  idSuffix,
181775
181906
  row,
@@ -188096,6 +188227,20 @@ Object.freeze({
188096
188227
  access: "view",
188097
188228
  role: "admin"
188098
188229
  },
188230
+ "mediaPlayer.channelDown": {
188231
+ capName: "media-player",
188232
+ capScope: "device",
188233
+ addonId: null,
188234
+ access: "create",
188235
+ role: "viewer"
188236
+ },
188237
+ "mediaPlayer.channelUp": {
188238
+ capName: "media-player",
188239
+ capScope: "device",
188240
+ addonId: null,
188241
+ access: "create",
188242
+ role: "viewer"
188243
+ },
188099
188244
  "mediaPlayer.getStatus": {
188100
188245
  capName: "media-player",
188101
188246
  capScope: "device",
@@ -188187,6 +188332,34 @@ Object.freeze({
188187
188332
  access: "create",
188188
188333
  role: "viewer"
188189
188334
  },
188335
+ "mediaPlayer.turnOff": {
188336
+ capName: "media-player",
188337
+ capScope: "device",
188338
+ addonId: null,
188339
+ access: "create",
188340
+ role: "viewer"
188341
+ },
188342
+ "mediaPlayer.turnOn": {
188343
+ capName: "media-player",
188344
+ capScope: "device",
188345
+ addonId: null,
188346
+ access: "create",
188347
+ role: "viewer"
188348
+ },
188349
+ "mediaPlayer.volumeDown": {
188350
+ capName: "media-player",
188351
+ capScope: "device",
188352
+ addonId: null,
188353
+ access: "create",
188354
+ role: "viewer"
188355
+ },
188356
+ "mediaPlayer.volumeUp": {
188357
+ capName: "media-player",
188358
+ capScope: "device",
188359
+ addonId: null,
188360
+ access: "create",
188361
+ role: "viewer"
188362
+ },
188190
188363
  "meshNetwork.getStatus": {
188191
188364
  capName: "mesh-network",
188192
188365
  capScope: "system",
@@ -191743,6 +191916,13 @@ Object.freeze({
191743
191916
  access: "create",
191744
191917
  role: "admin"
191745
191918
  },
191919
+ "remote.getAssumedStatus": {
191920
+ capName: "remote",
191921
+ capScope: "system",
191922
+ addonId: null,
191923
+ access: "view",
191924
+ role: "admin"
191925
+ },
191746
191926
  "remote.getConfig": {
191747
191927
  capName: "remote",
191748
191928
  capScope: "system",
@@ -195561,6 +195741,16 @@ Object.freeze({
195561
195741
  form: "single",
195562
195742
  optional: true
195563
195743
  }],
195744
+ "mediaPlayer.channelDown": [{
195745
+ name: "deviceId",
195746
+ form: "single",
195747
+ optional: false
195748
+ }],
195749
+ "mediaPlayer.channelUp": [{
195750
+ name: "deviceId",
195751
+ form: "single",
195752
+ optional: false
195753
+ }],
195564
195754
  "mediaPlayer.getStatus": [{
195565
195755
  name: "deviceId",
195566
195756
  form: "single",
@@ -195626,6 +195816,26 @@ Object.freeze({
195626
195816
  form: "single",
195627
195817
  optional: false
195628
195818
  }],
195819
+ "mediaPlayer.turnOff": [{
195820
+ name: "deviceId",
195821
+ form: "single",
195822
+ optional: false
195823
+ }],
195824
+ "mediaPlayer.turnOn": [{
195825
+ name: "deviceId",
195826
+ form: "single",
195827
+ optional: false
195828
+ }],
195829
+ "mediaPlayer.volumeDown": [{
195830
+ name: "deviceId",
195831
+ form: "single",
195832
+ optional: false
195833
+ }],
195834
+ "mediaPlayer.volumeUp": [{
195835
+ name: "deviceId",
195836
+ form: "single",
195837
+ optional: false
195838
+ }],
195629
195839
  "meter.getStatus": [{
195630
195840
  name: "deviceId",
195631
195841
  form: "single",
@@ -196791,6 +197001,11 @@ Object.freeze({
196791
197001
  form: "single",
196792
197002
  optional: true
196793
197003
  }],
197004
+ "remote.getAssumedStatus": [{
197005
+ name: "deviceId",
197006
+ form: "single",
197007
+ optional: false
197008
+ }],
196794
197009
  "remote.getConfig": [{
196795
197010
  name: "deviceId",
196796
197011
  form: "single",
@@ -198046,6 +198261,7 @@ var STATE_SUMMARY_VARS = [
198046
198261
  [...RULE_TEXT],
198047
198262
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
198048
198263
  ([...RULE_TEXT], [...COMBINED_ALARM]),
198264
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
198049
198265
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
198050
198266
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
198051
198267
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -208245,7 +208461,7 @@ var PirAccessory = class extends BaseDevice {
208245
208461
  async applySettingsPatch(patch) {
208246
208462
  await this.config.setAll(patch);
208247
208463
  if ("pirSensitive" in patch || "pirReduceAlarm" in patch || "pirIntervalS" in patch) try {
208248
- await this.pushConfigToFirmware(this.switchView().on);
208464
+ await this.pushConfigToFirmware(this.switchView().on === true);
208249
208465
  } catch (err) {
208250
208466
  this.ctx.logger.warn("pir firmware push failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
208251
208467
  throw err;