@camstack/addon-provider-homeassistant 1.2.635 → 1.2.636

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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.636] - 2026-10-29
11
+
12
+ ### Changed
13
+
14
+ - Media players report their state as reported
15
+
10
16
  ## [1.2.635] - 2026-10-28
11
17
 
12
18
  ### Changed
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("./dist-C_PMvyYa.js");
2
+ const require_dist = require("./dist-BS9DCd76.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_zlib = require("node:zlib");
5
5
  //#region src/ha-admin-link.ts
@@ -2443,6 +2443,8 @@ function readNumericAttr$1(attrs, key) {
2443
2443
  //#region src/devices/ha-media-player-device.ts
2444
2444
  var COLD_START$10 = {
2445
2445
  state: "off",
2446
+ stateSource: "reported",
2447
+ assumedFields: [],
2446
2448
  volumeLevel: null,
2447
2449
  isMuted: null,
2448
2450
  source: "",
@@ -2474,6 +2476,8 @@ var HaMediaPlayerDevice = class extends HaBaseChildDevice {
2474
2476
  const playerState = mapHaMediaPlayerState(state.state);
2475
2477
  const slice = {
2476
2478
  state: playerState ?? "off",
2479
+ stateSource: "reported",
2480
+ assumedFields: [],
2477
2481
  volumeLevel: readVolumeAsPercent(attrs),
2478
2482
  isMuted: readBooleanAttr(attrs, "is_volume_muted"),
2479
2483
  source: readStringAttr$2(attrs, "source") ?? "",
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as lawnMowerControlCapability, $t as union, A as buttonCapability, At as weatherCapability, B as coverCapability, Bt as defineRecordKinds, C as batteryCapability, Ct as tryConvertDelta, D as brokerCapability, Dt as valveCapability, E as brightnessCapability, Et as vacuumControlCapability, F as connectivityCapability, G as eventEmitterCapability, Gt as array, H as deviceAdoptionCapability, It as RecordSecretUnavailableError, J as gasCapability, Jt as literal, K as fanControlCapability, Kt as boolean, Lt as baseUnitOf, M as carbonMonoxideCapability, Mt as DeviceRole, N as climateControlCapability, Nt as DeviceType, O as buildAddonRouteProvider, Ot as vibrationCapability, P as colorCapability, Pt as errMsg, Q as ingestReading, Qt as string, R as contactCapability, Rt as createEvent, S as automationControlCapability, St as temperatureSensorCapability, T as binaryCapability, Tt as updateCapability, V as deviceAdminLinkCapability, Vt as entryBody, W as enumSensorCapability, Wt as _enum, X as humiditySensorCapability, Xt as object, Y as humidifierCapability, Yt as number, Z as imageCapability, Zt as record, _ as accessoriesCapability, _t as runningStateCapability, at as notifierCapability, b as alarmPanelCapability, bt as switchCapability, ct as parseAdminBase, dt as presenceCapability, en as unknown, et as lockControlCapability, ft as pressureSensorCapability, g as TargetSchema, gt as runningFromVacuumState, h as RUNNING_STATE_COLD, ht as runningFromMediaPlayer, it as notificationOutputCapability, j as calendarSourceCapability, jt as DeviceFeature, k as buildDeviceAdminUrl, kt as waterHeaterCapability, lt as powerMeterCapability, mt as runningFromLawnMower, n as BaseDevice, nn as EventCategory, nt as motionCapability, ot as numericSensorCapability, pt as quantityFromUnit, q as floodCapability, qt as discriminatedUnion, r as BaseDeviceProvider, rt as normalizeUnit, tn as url, tt as mediaPlayerCapability, u as EnumSensorDateTimeFormatSchema, ut as prepareNotification, v as addonRoutesCapability, vt as scriptRunnerCapability, w as bestLocationMatch, wt as tryConvertUnit, x as ambientLightSensorCapability, xt as tamperCapability, y as airQualitySensorCapability, yt as smokeCapability, z as controlCapability, zt as defineEntryKind } from "./dist-CYl0u8cF.mjs";
1
+ import { $ as lawnMowerControlCapability, $t as union, A as buttonCapability, At as weatherCapability, B as coverCapability, Bt as defineRecordKinds, C as batteryCapability, Ct as tryConvertDelta, D as brokerCapability, Dt as valveCapability, E as brightnessCapability, Et as vacuumControlCapability, F as connectivityCapability, G as eventEmitterCapability, Gt as array, H as deviceAdoptionCapability, It as RecordSecretUnavailableError, J as gasCapability, Jt as literal, K as fanControlCapability, Kt as boolean, Lt as baseUnitOf, M as carbonMonoxideCapability, Mt as DeviceRole, N as climateControlCapability, Nt as DeviceType, O as buildAddonRouteProvider, Ot as vibrationCapability, P as colorCapability, Pt as errMsg, Q as ingestReading, Qt as string, R as contactCapability, Rt as createEvent, S as automationControlCapability, St as temperatureSensorCapability, T as binaryCapability, Tt as updateCapability, V as deviceAdminLinkCapability, Vt as entryBody, W as enumSensorCapability, Wt as _enum, X as humiditySensorCapability, Xt as object, Y as humidifierCapability, Yt as number, Z as imageCapability, Zt as record, _ as accessoriesCapability, _t as runningStateCapability, at as notifierCapability, b as alarmPanelCapability, bt as switchCapability, ct as parseAdminBase, dt as presenceCapability, en as unknown, et as lockControlCapability, ft as pressureSensorCapability, g as TargetSchema, gt as runningFromVacuumState, h as RUNNING_STATE_COLD, ht as runningFromMediaPlayer, it as notificationOutputCapability, j as calendarSourceCapability, jt as DeviceFeature, k as buildDeviceAdminUrl, kt as waterHeaterCapability, lt as powerMeterCapability, mt as runningFromLawnMower, n as BaseDevice, nn as EventCategory, nt as motionCapability, ot as numericSensorCapability, pt as quantityFromUnit, q as floodCapability, qt as discriminatedUnion, r as BaseDeviceProvider, rt as normalizeUnit, tn as url, tt as mediaPlayerCapability, u as EnumSensorDateTimeFormatSchema, ut as prepareNotification, v as addonRoutesCapability, vt as scriptRunnerCapability, w as bestLocationMatch, wt as tryConvertUnit, x as ambientLightSensorCapability, xt as tamperCapability, y as airQualitySensorCapability, yt as smokeCapability, z as controlCapability, zt as defineEntryKind } from "./dist-BusXPPvn.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-admin-link.ts
@@ -2442,6 +2442,8 @@ function readNumericAttr$1(attrs, key) {
2442
2442
  //#region src/devices/ha-media-player-device.ts
2443
2443
  var COLD_START$10 = {
2444
2444
  state: "off",
2445
+ stateSource: "reported",
2446
+ assumedFields: [],
2445
2447
  volumeLevel: null,
2446
2448
  isMuted: null,
2447
2449
  source: "",
@@ -2473,6 +2475,8 @@ var HaMediaPlayerDevice = class extends HaBaseChildDevice {
2473
2475
  const playerState = mapHaMediaPlayerState(state.state);
2474
2476
  const slice = {
2475
2477
  state: playerState ?? "off",
2478
+ stateSource: "reported",
2479
+ assumedFields: [],
2476
2480
  volumeLevel: readVolumeAsPercent(attrs),
2477
2481
  isMuted: readBooleanAttr(attrs, "is_volume_muted"),
2478
2482
  source: readStringAttr$2(attrs, "source") ?? "",
@@ -5580,7 +5580,7 @@ var ZodIssueCode = {
5580
5580
  var ZodFirstPartyTypeKind;
5581
5581
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5582
5582
  //#endregion
5583
- //#region ../types/dist/sleep-BAvUCi_2.mjs
5583
+ //#region ../types/dist/sleep-DJws6ho7.mjs
5584
5584
  /**
5585
5585
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5586
5586
  * window to float samples (D455).
@@ -9094,6 +9094,7 @@ var CAP_NAMES = Object.freeze([
9094
9094
  "recording-onboard",
9095
9095
  "recording-signal",
9096
9096
  "records",
9097
+ "remote",
9097
9098
  "running-state",
9098
9099
  "scene-monitor",
9099
9100
  "script-runner",
@@ -9117,6 +9118,7 @@ var CAP_NAMES = Object.freeze([
9117
9118
  "system",
9118
9119
  "tamper",
9119
9120
  "temperature-sensor",
9121
+ "template",
9120
9122
  "terminal-session",
9121
9123
  "toast",
9122
9124
  "training",
@@ -10057,6 +10059,11 @@ Object.freeze({
10057
10059
  "standby"
10058
10060
  ]
10059
10061
  },
10062
+ {
10063
+ "path": "stateSource",
10064
+ "valueType": "enum",
10065
+ "enumValues": ["reported", "assumed"]
10066
+ },
10060
10067
  {
10061
10068
  "path": "volumeLevel",
10062
10069
  "valueType": "number"
@@ -10332,6 +10339,18 @@ Object.freeze({
10332
10339
  {
10333
10340
  "path": "volume",
10334
10341
  "valueType": "number"
10342
+ },
10343
+ {
10344
+ "path": "lastFeedGrams",
10345
+ "valueType": "number"
10346
+ },
10347
+ {
10348
+ "path": "lastFeedHopper1",
10349
+ "valueType": "number"
10350
+ },
10351
+ {
10352
+ "path": "lastFeedHopper2",
10353
+ "valueType": "number"
10335
10354
  }
10336
10355
  ],
10337
10356
  "power-meter": [
@@ -16806,9 +16825,21 @@ var AlertSeveritySchema = _enum([
16806
16825
  "error",
16807
16826
  "critical"
16808
16827
  ]);
16828
+ /**
16829
+ * An action that RUNS something instead of going somewhere: the admin UI calls
16830
+ * the addon's custom action (`addons.custom`) with exactly these fields. The
16831
+ * producer owns the meaning; the UI knows nothing about the addon or the kind.
16832
+ */
16833
+ var AlertActionInvokeSchema = object({
16834
+ addonId: string().min(1),
16835
+ action: string().min(1),
16836
+ input: record(string(), unknown()).optional()
16837
+ });
16838
+ /** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
16809
16839
  var AlertActionSchema = object({
16810
16840
  label: string(),
16811
16841
  href: string().optional(),
16842
+ invoke: AlertActionInvokeSchema.optional(),
16812
16843
  /**
16813
16844
  * How `href` is followed. Absent / `app`: an admin-ui route (client-side).
16814
16845
  * `server`: a route the HUB serves (an addon HTTP route such as an OAuth
@@ -59213,6 +59244,318 @@ onBrightnessChanged: { data: object({
59213
59244
  } } }
59214
59245
  };
59215
59246
  /**
59247
+ * The role vocabulary of a remote (D963): what a button MEANS, independent of
59248
+ * how it is wired. A layout template places buttons by role; a device binds a
59249
+ * role to an action; an exporter asks for a role by name. Roles are shared so
59250
+ * one layout fits every appliance and one voice command fits every binding.
59251
+ *
59252
+ * A role outside this list is `custom:<key>` — the operator's own button (a
59253
+ * SmartIR source, a channel preset). The key is a lowercase slug.
59254
+ */
59255
+ var REMOTE_KNOWN_ROLES = [
59256
+ "power",
59257
+ "power_on",
59258
+ "power_off",
59259
+ "volume_up",
59260
+ "volume_down",
59261
+ "mute",
59262
+ "channel_up",
59263
+ "channel_down",
59264
+ "up",
59265
+ "down",
59266
+ "left",
59267
+ "right",
59268
+ "ok",
59269
+ "back",
59270
+ "home",
59271
+ "menu",
59272
+ "info",
59273
+ "guide",
59274
+ "exit",
59275
+ "input",
59276
+ "play",
59277
+ "pause",
59278
+ "play_pause",
59279
+ "stop",
59280
+ "next",
59281
+ "previous",
59282
+ "fast_forward",
59283
+ "rewind",
59284
+ "digit_0",
59285
+ "digit_1",
59286
+ "digit_2",
59287
+ "digit_3",
59288
+ "digit_4",
59289
+ "digit_5",
59290
+ "digit_6",
59291
+ "digit_7",
59292
+ "digit_8",
59293
+ "digit_9"
59294
+ ];
59295
+ var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
59296
+ var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
59297
+ function isRemoteKnownRole(value) {
59298
+ return KNOWN_ROLES.has(value);
59299
+ }
59300
+ function isRemoteCustomKey(key) {
59301
+ return CUSTOM_KEY_RE.test(key);
59302
+ }
59303
+ /** The key of a `custom:<key>` role, or null for any other string. */
59304
+ function customKeyOfRole(role) {
59305
+ if (!role.startsWith("custom:")) return null;
59306
+ const key = role.slice(7);
59307
+ return isRemoteCustomKey(key) ? key : null;
59308
+ }
59309
+ function isRemoteRole(value) {
59310
+ return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
59311
+ }
59312
+ var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
59313
+ var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
59314
+ var RemoteCustomButtonSchema = object({
59315
+ /** The slug after `custom:` in the role. */
59316
+ key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
59317
+ /** What the operator calls it, and what a voice command may name. */
59318
+ name: string().min(1).max(60)
59319
+ });
59320
+ var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
59321
+ var RemoteConfigSchema = object({
59322
+ layoutTemplateId: string().min(1).nullable(),
59323
+ /**
59324
+ * The transmitter device new bindings and an import send through. A binding
59325
+ * names its own device, so one command may override it.
59326
+ */
59327
+ defaultTransmitterId: number().int().nonnegative().nullable().default(null),
59328
+ /** Keyed by role. A role with no entry falls back to the native cap. */
59329
+ bindings: record(string(), RemoteBindingSchema),
59330
+ customButtons: array(RemoteCustomButtonSchema).max(100),
59331
+ power: object({ mode: RemotePowerModeSchema })
59332
+ }).superRefine((config, ctx) => {
59333
+ const roles = Object.keys(config.bindings);
59334
+ if (roles.length > 200) ctx.addIssue({
59335
+ code: "custom",
59336
+ message: "too many bindings",
59337
+ path: ["bindings"]
59338
+ });
59339
+ for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
59340
+ code: "custom",
59341
+ message: `"${role}" is not a role`,
59342
+ path: ["bindings", role]
59343
+ });
59344
+ const keys = /* @__PURE__ */ new Set();
59345
+ config.customButtons.forEach((button, index) => {
59346
+ if (keys.has(button.key)) ctx.addIssue({
59347
+ code: "custom",
59348
+ message: `custom button "${button.key}" is listed twice`,
59349
+ path: [
59350
+ "customButtons",
59351
+ index,
59352
+ "key"
59353
+ ]
59354
+ });
59355
+ keys.add(button.key);
59356
+ });
59357
+ for (const role of roles) {
59358
+ const key = customKeyOfRole(role);
59359
+ if (key !== null && !keys.has(key)) ctx.addIssue({
59360
+ code: "custom",
59361
+ message: `${role} is bound but has no entry in customButtons`,
59362
+ path: ["bindings", role]
59363
+ });
59364
+ }
59365
+ });
59366
+ object({
59367
+ power: object({
59368
+ state: _enum(["on", "off"]),
59369
+ at: number()
59370
+ }).nullable(),
59371
+ muted: object({
59372
+ value: boolean(),
59373
+ at: number()
59374
+ }).nullable()
59375
+ });
59376
+ var RemoteLayoutButtonSchema = object({
59377
+ id: string().min(1).max(40),
59378
+ /** 0-based grid position. */
59379
+ row: number().int().min(0).max(24),
59380
+ col: number().int().min(0).max(24),
59381
+ rowSpan: number().int().min(1).max(24),
59382
+ colSpan: number().int().min(1).max(24),
59383
+ icon: string().min(1).max(60).optional(),
59384
+ label: string().min(1).max(40).optional(),
59385
+ role: RemoteRoleSchema
59386
+ });
59387
+ object({
59388
+ columns: number().int().min(1).max(24),
59389
+ rows: number().int().min(1).max(24),
59390
+ buttons: array(RemoteLayoutButtonSchema).max(200)
59391
+ }).superRefine((grid, ctx) => {
59392
+ const ids = /* @__PURE__ */ new Set();
59393
+ const taken = /* @__PURE__ */ new Map();
59394
+ grid.buttons.forEach((button, index) => {
59395
+ if (ids.has(button.id)) ctx.addIssue({
59396
+ code: "custom",
59397
+ message: `button id "${button.id}" is used twice`,
59398
+ path: [
59399
+ "buttons",
59400
+ index,
59401
+ "id"
59402
+ ]
59403
+ });
59404
+ ids.add(button.id);
59405
+ if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
59406
+ ctx.addIssue({
59407
+ code: "custom",
59408
+ message: `button "${button.id}" leaves the grid`,
59409
+ path: ["buttons", index]
59410
+ });
59411
+ return;
59412
+ }
59413
+ for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
59414
+ const cell = `${r}:${c}`;
59415
+ const other = taken.get(cell);
59416
+ if (other !== void 0) {
59417
+ ctx.addIssue({
59418
+ code: "custom",
59419
+ message: `buttons "${other}" and "${button.id}" overlap`,
59420
+ path: ["buttons", index]
59421
+ });
59422
+ return;
59423
+ }
59424
+ taken.set(cell, button.id);
59425
+ }
59426
+ });
59427
+ });
59428
+ var RemoteBoundCommandSchema = object({
59429
+ role: RemoteRoleSchema,
59430
+ /** The operator's name for a custom button; absent for a known role. */
59431
+ label: string().optional(),
59432
+ custom: boolean()
59433
+ });
59434
+ var RemoteCommandListSchema = object({
59435
+ layoutTemplateId: string().nullable(),
59436
+ power: object({ mode: RemotePowerModeSchema }),
59437
+ /** Only the roles that are BOUND — the ones a press can reach. */
59438
+ commands: array(RemoteBoundCommandSchema)
59439
+ });
59440
+ var RemoteRefusalReasonSchema = _enum([
59441
+ "no-remote",
59442
+ "unbound-role",
59443
+ "action-failed"
59444
+ ]);
59445
+ var RemoteSendResultSchema = discriminatedUnion("status", [
59446
+ object({
59447
+ status: literal("sent"),
59448
+ /** How many times the action ran. */
59449
+ sends: number().int().min(1)
59450
+ }),
59451
+ object({
59452
+ status: literal("skipped"),
59453
+ reason: literal("already-in-state")
59454
+ }),
59455
+ object({
59456
+ status: literal("refused"),
59457
+ reason: RemoteRefusalReasonSchema,
59458
+ detail: string().optional()
59459
+ })
59460
+ ]);
59461
+ var RemoteMediaCommandSchema = _enum([
59462
+ "play",
59463
+ "pause",
59464
+ "stop",
59465
+ "next",
59466
+ "previous",
59467
+ "setMute",
59468
+ "selectSource"
59469
+ ]);
59470
+ /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
59471
+ var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
59472
+ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
59473
+ status: literal("refused"),
59474
+ reason: _enum(["unknown-template", "not-a-media-player"]),
59475
+ detail: string()
59476
+ })]);
59477
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
59478
+ DeviceType.MediaPlayer;
59479
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
59480
+ kind: "mutation",
59481
+ auth: "admin"
59482
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
59483
+ role: RemoteRoleSchema,
59484
+ /** Sends in a row (volume steps). */
59485
+ repeat: number().int().min(1).max(50).default(1)
59486
+ }), RemoteSendResultSchema, {
59487
+ kind: "mutation",
59488
+ auth: "protected"
59489
+ }), method(deviceInput.extend({
59490
+ command: RemoteMediaCommandSchema,
59491
+ muted: boolean().optional(),
59492
+ source: string().optional(),
59493
+ repeat: number().int().min(1).max(50).default(1)
59494
+ }), RemoteMediaCommandResultSchema, {
59495
+ kind: "mutation",
59496
+ auth: "protected"
59497
+ });
59498
+ var TemplateKindSchema = _enum(["remote"]);
59499
+ /**
59500
+ * template — the generic store of reusable, named operator data (D963). A
59501
+ * record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
59502
+ * button grid of a remote) and the schema each payload must satisfy are
59503
+ * declared by the system in `template-kinds.ts`. Nothing here is specific to a
59504
+ * kind: the engine validates a payload against its kind's schema and, on a
59505
+ * delete, asks the kind's owner whether anything still points at the record.
59506
+ *
59507
+ * Every refusal is a typed result — a UI says "unknown kind" or names the
59508
+ * devices that still use a template, without parsing text.
59509
+ */
59510
+ var TemplateRecordSchema = object({
59511
+ id: string().min(1),
59512
+ kind: TemplateKindSchema,
59513
+ name: string().min(1).max(120),
59514
+ /** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
59515
+ payload: unknown(),
59516
+ createdAt: number(),
59517
+ updatedAt: number()
59518
+ });
59519
+ var TemplateWriteResultSchema = discriminatedUnion("status", [object({
59520
+ status: literal("saved"),
59521
+ template: TemplateRecordSchema
59522
+ }), object({
59523
+ status: literal("refused"),
59524
+ reason: _enum(["invalid-payload", "not-found"]),
59525
+ detail: string()
59526
+ })]);
59527
+ /** A device still pointing at a template. */
59528
+ var TemplateUserSchema = object({
59529
+ deviceId: number().int().nonnegative(),
59530
+ name: string()
59531
+ });
59532
+ var TemplateDeleteResultSchema = discriminatedUnion("status", [
59533
+ object({ status: literal("deleted") }),
59534
+ object({ status: literal("not-found") }),
59535
+ object({
59536
+ status: literal("in-use"),
59537
+ devices: array(TemplateUserSchema).min(1)
59538
+ })
59539
+ ]);
59540
+ method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
59541
+ kind: TemplateKindSchema,
59542
+ name: string().min(1).max(120),
59543
+ payload: unknown()
59544
+ }), TemplateWriteResultSchema, {
59545
+ kind: "mutation",
59546
+ auth: "admin"
59547
+ }), method(object({
59548
+ id: string().min(1),
59549
+ name: string().min(1).max(120).optional(),
59550
+ payload: unknown().optional()
59551
+ }), TemplateWriteResultSchema, {
59552
+ kind: "mutation",
59553
+ auth: "admin"
59554
+ }), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
59555
+ kind: "mutation",
59556
+ auth: "admin"
59557
+ });
59558
+ /**
59216
59559
  * button — device-scoped capability for HA `button.*` / `input_button.*`
59217
59560
  * fire-only actuators. A button entity has no readable state — pressing it
59218
59561
  * triggers an action on the HA side. There is no `status` / `runtimeState`:
@@ -63414,9 +63757,35 @@ var MediaInfoSchema = object({
63414
63757
  /** Optional cover-art / thumbnail URL. */
63415
63758
  imageUrl: string().optional()
63416
63759
  });
63760
+ /**
63761
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
63762
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
63763
+ * tracks what it last SENT; it moves only after a send was accepted, and a
63764
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
63765
+ * guess, never as a reading.
63766
+ */
63767
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
63768
+ /** The fields of a media-player status a driver can only guess. */
63769
+ var MediaPlayerAssumedFieldSchema = _enum([
63770
+ "state",
63771
+ "volumeLevel",
63772
+ "isMuted",
63773
+ "source"
63774
+ ]);
63417
63775
  var MediaPlayerStatusSchema = object({
63418
63776
  /** Playback lifecycle state. */
63419
63777
  state: MediaPlayerStateSchema,
63778
+ /**
63779
+ * Whether the state fields are readings or the driver's own bookkeeping.
63780
+ * A slice written before this field existed parses as `reported`.
63781
+ */
63782
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
63783
+ /**
63784
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
63785
+ * this is not empty; a field not listed here is a reading even then (power
63786
+ * from a running-state source, mute guessed from the last send).
63787
+ */
63788
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
63420
63789
  /** Volume as 0..100 inclusive. Null when the device has no volume
63421
63790
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
63422
63791
  volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -65379,6 +65748,14 @@ var PetFeederStatusSchema = object({
65379
65748
  feedSound: boolean(),
65380
65749
  /** Speaker / prompt volume level (device-scaled integer). */
65381
65750
  volume: number().meta(readingMeta("none")),
65751
+ /** Portion (grams) of the last manual feed sent from a single-hopper
65752
+ * stepper — the default the next manual feed starts from. Persisted per
65753
+ * device by the provider; null until a manual feed has been sent. */
65754
+ lastFeedGrams: gramsPortion.nullable(),
65755
+ /** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
65756
+ lastFeedHopper1: gramsPortion.nullable(),
65757
+ /** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
65758
+ lastFeedHopper2: gramsPortion.nullable(),
65382
65759
  /** Ms epoch when the slice was last refreshed from the cloud. */
65383
65760
  lastFetchedAt: number()
65384
65761
  });
@@ -71424,6 +71801,14 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
71424
71801
  kind: "mutation",
71425
71802
  auth: "admin"
71426
71803
  });
71804
+ discriminatedUnion("kind", [object({
71805
+ kind: literal("raw"),
71806
+ timings: array(number().int()),
71807
+ settings: TransmitSettingsSchema.optional()
71808
+ }), object({
71809
+ kind: literal("pronto"),
71810
+ code: string()
71811
+ })]);
71427
71812
  function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
71428
71813
  if (running === null) return null;
71429
71814
  const prevRunning = previous?.running ?? null;
@@ -71861,7 +72246,7 @@ function tryConvertDelta(value, from, to) {
71861
72246
  return shifted - origin;
71862
72247
  }
71863
72248
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
71864
- 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.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, 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.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.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.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.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
72249
+ 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.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, 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.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.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.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.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;
71865
72250
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
71866
72251
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
71867
72252
  new Set(CAP_NAMES);
@@ -81151,6 +81536,41 @@ Object.freeze({
81151
81536
  access: "create",
81152
81537
  role: "admin"
81153
81538
  },
81539
+ "remote.getConfig": {
81540
+ capName: "remote",
81541
+ capScope: "system",
81542
+ addonId: null,
81543
+ access: "view",
81544
+ role: "admin"
81545
+ },
81546
+ "remote.listCommands": {
81547
+ capName: "remote",
81548
+ capScope: "system",
81549
+ addonId: null,
81550
+ access: "view",
81551
+ role: "admin"
81552
+ },
81553
+ "remote.sendCommand": {
81554
+ capName: "remote",
81555
+ capScope: "system",
81556
+ addonId: null,
81557
+ access: "create",
81558
+ role: "admin"
81559
+ },
81560
+ "remote.sendMediaCommand": {
81561
+ capName: "remote",
81562
+ capScope: "system",
81563
+ addonId: null,
81564
+ access: "create",
81565
+ role: "admin"
81566
+ },
81567
+ "remote.setConfig": {
81568
+ capName: "remote",
81569
+ capScope: "system",
81570
+ addonId: null,
81571
+ access: "create",
81572
+ role: "admin"
81573
+ },
81154
81574
  "runningState.getStatus": {
81155
81575
  capName: "running-state",
81156
81576
  capScope: "device",
@@ -82341,6 +82761,41 @@ Object.freeze({
82341
82761
  access: "view",
82342
82762
  role: "viewer"
82343
82763
  },
82764
+ "template.create": {
82765
+ capName: "template",
82766
+ capScope: "system",
82767
+ addonId: null,
82768
+ access: "create",
82769
+ role: "admin"
82770
+ },
82771
+ "template.delete": {
82772
+ capName: "template",
82773
+ capScope: "system",
82774
+ addonId: null,
82775
+ access: "delete",
82776
+ role: "admin"
82777
+ },
82778
+ "template.get": {
82779
+ capName: "template",
82780
+ capScope: "system",
82781
+ addonId: null,
82782
+ access: "view",
82783
+ role: "admin"
82784
+ },
82785
+ "template.list": {
82786
+ capName: "template",
82787
+ capScope: "system",
82788
+ addonId: null,
82789
+ access: "view",
82790
+ role: "admin"
82791
+ },
82792
+ "template.update": {
82793
+ capName: "template",
82794
+ capScope: "system",
82795
+ addonId: null,
82796
+ access: "create",
82797
+ role: "admin"
82798
+ },
82344
82799
  "terminalSession.adoptLegacyMonitor": {
82345
82800
  capName: "terminal-session",
82346
82801
  capScope: "system",
@@ -87172,6 +87627,7 @@ var SYSTEM_CAP_VOCABULARY = {
87172
87627
  "recording-archive": system(STORAGE),
87173
87628
  "recording-export": system("recording exports — requested from the timeline, not an automation step"),
87174
87629
  records: system(INTERNAL),
87630
+ remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
87175
87631
  "server-management": system(CLUSTER),
87176
87632
  "settings-store": system(INTERNAL),
87177
87633
  "smtp-provider": system(INTERNAL),
@@ -87184,6 +87640,7 @@ var SYSTEM_CAP_VOCABULARY = {
87184
87640
  "storage-provider": system(STORAGE),
87185
87641
  "stream-broker": system(PIPELINE),
87186
87642
  system: system(CLUSTER),
87643
+ template: system("operator-authored templates — edited in their own editor, never actuated"),
87187
87644
  "terminal-session": system(CLUSTER),
87188
87645
  toast: system(UI_PLUMBING),
87189
87646
  training: system(ML),
@@ -89621,6 +90078,31 @@ Object.freeze({
89621
90078
  form: "single",
89622
90079
  optional: true
89623
90080
  }],
90081
+ "remote.getConfig": [{
90082
+ name: "deviceId",
90083
+ form: "single",
90084
+ optional: false
90085
+ }],
90086
+ "remote.listCommands": [{
90087
+ name: "deviceId",
90088
+ form: "single",
90089
+ optional: false
90090
+ }],
90091
+ "remote.sendCommand": [{
90092
+ name: "deviceId",
90093
+ form: "single",
90094
+ optional: false
90095
+ }],
90096
+ "remote.sendMediaCommand": [{
90097
+ name: "deviceId",
90098
+ form: "single",
90099
+ optional: false
90100
+ }],
90101
+ "remote.setConfig": [{
90102
+ name: "deviceId",
90103
+ form: "single",
90104
+ optional: false
90105
+ }],
89624
90106
  "runningState.getStatus": [{
89625
90107
  name: "deviceId",
89626
90108
  form: "single",
@@ -91778,14 +92260,6 @@ function bestLocationMatch(externalName, existing, threshold = .8) {
91778
92260
  String.raw`(?<=^|["'(\s>,\[{])`;
91779
92261
  var MB = 1024 * 1024;
91780
92262
  1024 * MB, 3072 * MB;
91781
- discriminatedUnion("kind", [object({
91782
- kind: literal("raw"),
91783
- timings: array(number().int()),
91784
- settings: TransmitSettingsSchema.optional()
91785
- }), object({
91786
- kind: literal("pronto"),
91787
- code: string()
91788
- })]);
91789
92263
  object({
91790
92264
  manufacturer: string().optional(),
91791
92265
  supportedModels: array(string()).optional(),
@@ -5579,7 +5579,7 @@ var ZodIssueCode = {
5579
5579
  var ZodFirstPartyTypeKind;
5580
5580
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5581
5581
  //#endregion
5582
- //#region ../types/dist/sleep-BAvUCi_2.mjs
5582
+ //#region ../types/dist/sleep-DJws6ho7.mjs
5583
5583
  /**
5584
5584
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5585
5585
  * window to float samples (D455).
@@ -9093,6 +9093,7 @@ var CAP_NAMES = Object.freeze([
9093
9093
  "recording-onboard",
9094
9094
  "recording-signal",
9095
9095
  "records",
9096
+ "remote",
9096
9097
  "running-state",
9097
9098
  "scene-monitor",
9098
9099
  "script-runner",
@@ -9116,6 +9117,7 @@ var CAP_NAMES = Object.freeze([
9116
9117
  "system",
9117
9118
  "tamper",
9118
9119
  "temperature-sensor",
9120
+ "template",
9119
9121
  "terminal-session",
9120
9122
  "toast",
9121
9123
  "training",
@@ -10056,6 +10058,11 @@ Object.freeze({
10056
10058
  "standby"
10057
10059
  ]
10058
10060
  },
10061
+ {
10062
+ "path": "stateSource",
10063
+ "valueType": "enum",
10064
+ "enumValues": ["reported", "assumed"]
10065
+ },
10059
10066
  {
10060
10067
  "path": "volumeLevel",
10061
10068
  "valueType": "number"
@@ -10331,6 +10338,18 @@ Object.freeze({
10331
10338
  {
10332
10339
  "path": "volume",
10333
10340
  "valueType": "number"
10341
+ },
10342
+ {
10343
+ "path": "lastFeedGrams",
10344
+ "valueType": "number"
10345
+ },
10346
+ {
10347
+ "path": "lastFeedHopper1",
10348
+ "valueType": "number"
10349
+ },
10350
+ {
10351
+ "path": "lastFeedHopper2",
10352
+ "valueType": "number"
10334
10353
  }
10335
10354
  ],
10336
10355
  "power-meter": [
@@ -16805,9 +16824,21 @@ var AlertSeveritySchema = _enum([
16805
16824
  "error",
16806
16825
  "critical"
16807
16826
  ]);
16827
+ /**
16828
+ * An action that RUNS something instead of going somewhere: the admin UI calls
16829
+ * the addon's custom action (`addons.custom`) with exactly these fields. The
16830
+ * producer owns the meaning; the UI knows nothing about the addon or the kind.
16831
+ */
16832
+ var AlertActionInvokeSchema = object({
16833
+ addonId: string().min(1),
16834
+ action: string().min(1),
16835
+ input: record(string(), unknown()).optional()
16836
+ });
16837
+ /** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
16808
16838
  var AlertActionSchema = object({
16809
16839
  label: string(),
16810
16840
  href: string().optional(),
16841
+ invoke: AlertActionInvokeSchema.optional(),
16811
16842
  /**
16812
16843
  * How `href` is followed. Absent / `app`: an admin-ui route (client-side).
16813
16844
  * `server`: a route the HUB serves (an addon HTTP route such as an OAuth
@@ -59212,6 +59243,318 @@ onBrightnessChanged: { data: object({
59212
59243
  } } }
59213
59244
  };
59214
59245
  /**
59246
+ * The role vocabulary of a remote (D963): what a button MEANS, independent of
59247
+ * how it is wired. A layout template places buttons by role; a device binds a
59248
+ * role to an action; an exporter asks for a role by name. Roles are shared so
59249
+ * one layout fits every appliance and one voice command fits every binding.
59250
+ *
59251
+ * A role outside this list is `custom:<key>` — the operator's own button (a
59252
+ * SmartIR source, a channel preset). The key is a lowercase slug.
59253
+ */
59254
+ var REMOTE_KNOWN_ROLES = [
59255
+ "power",
59256
+ "power_on",
59257
+ "power_off",
59258
+ "volume_up",
59259
+ "volume_down",
59260
+ "mute",
59261
+ "channel_up",
59262
+ "channel_down",
59263
+ "up",
59264
+ "down",
59265
+ "left",
59266
+ "right",
59267
+ "ok",
59268
+ "back",
59269
+ "home",
59270
+ "menu",
59271
+ "info",
59272
+ "guide",
59273
+ "exit",
59274
+ "input",
59275
+ "play",
59276
+ "pause",
59277
+ "play_pause",
59278
+ "stop",
59279
+ "next",
59280
+ "previous",
59281
+ "fast_forward",
59282
+ "rewind",
59283
+ "digit_0",
59284
+ "digit_1",
59285
+ "digit_2",
59286
+ "digit_3",
59287
+ "digit_4",
59288
+ "digit_5",
59289
+ "digit_6",
59290
+ "digit_7",
59291
+ "digit_8",
59292
+ "digit_9"
59293
+ ];
59294
+ var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
59295
+ var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
59296
+ function isRemoteKnownRole(value) {
59297
+ return KNOWN_ROLES.has(value);
59298
+ }
59299
+ function isRemoteCustomKey(key) {
59300
+ return CUSTOM_KEY_RE.test(key);
59301
+ }
59302
+ /** The key of a `custom:<key>` role, or null for any other string. */
59303
+ function customKeyOfRole(role) {
59304
+ if (!role.startsWith("custom:")) return null;
59305
+ const key = role.slice(7);
59306
+ return isRemoteCustomKey(key) ? key : null;
59307
+ }
59308
+ function isRemoteRole(value) {
59309
+ return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
59310
+ }
59311
+ var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
59312
+ var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
59313
+ var RemoteCustomButtonSchema = object({
59314
+ /** The slug after `custom:` in the role. */
59315
+ key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
59316
+ /** What the operator calls it, and what a voice command may name. */
59317
+ name: string().min(1).max(60)
59318
+ });
59319
+ var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
59320
+ var RemoteConfigSchema = object({
59321
+ layoutTemplateId: string().min(1).nullable(),
59322
+ /**
59323
+ * The transmitter device new bindings and an import send through. A binding
59324
+ * names its own device, so one command may override it.
59325
+ */
59326
+ defaultTransmitterId: number().int().nonnegative().nullable().default(null),
59327
+ /** Keyed by role. A role with no entry falls back to the native cap. */
59328
+ bindings: record(string(), RemoteBindingSchema),
59329
+ customButtons: array(RemoteCustomButtonSchema).max(100),
59330
+ power: object({ mode: RemotePowerModeSchema })
59331
+ }).superRefine((config, ctx) => {
59332
+ const roles = Object.keys(config.bindings);
59333
+ if (roles.length > 200) ctx.addIssue({
59334
+ code: "custom",
59335
+ message: "too many bindings",
59336
+ path: ["bindings"]
59337
+ });
59338
+ for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
59339
+ code: "custom",
59340
+ message: `"${role}" is not a role`,
59341
+ path: ["bindings", role]
59342
+ });
59343
+ const keys = /* @__PURE__ */ new Set();
59344
+ config.customButtons.forEach((button, index) => {
59345
+ if (keys.has(button.key)) ctx.addIssue({
59346
+ code: "custom",
59347
+ message: `custom button "${button.key}" is listed twice`,
59348
+ path: [
59349
+ "customButtons",
59350
+ index,
59351
+ "key"
59352
+ ]
59353
+ });
59354
+ keys.add(button.key);
59355
+ });
59356
+ for (const role of roles) {
59357
+ const key = customKeyOfRole(role);
59358
+ if (key !== null && !keys.has(key)) ctx.addIssue({
59359
+ code: "custom",
59360
+ message: `${role} is bound but has no entry in customButtons`,
59361
+ path: ["bindings", role]
59362
+ });
59363
+ }
59364
+ });
59365
+ object({
59366
+ power: object({
59367
+ state: _enum(["on", "off"]),
59368
+ at: number()
59369
+ }).nullable(),
59370
+ muted: object({
59371
+ value: boolean(),
59372
+ at: number()
59373
+ }).nullable()
59374
+ });
59375
+ var RemoteLayoutButtonSchema = object({
59376
+ id: string().min(1).max(40),
59377
+ /** 0-based grid position. */
59378
+ row: number().int().min(0).max(24),
59379
+ col: number().int().min(0).max(24),
59380
+ rowSpan: number().int().min(1).max(24),
59381
+ colSpan: number().int().min(1).max(24),
59382
+ icon: string().min(1).max(60).optional(),
59383
+ label: string().min(1).max(40).optional(),
59384
+ role: RemoteRoleSchema
59385
+ });
59386
+ object({
59387
+ columns: number().int().min(1).max(24),
59388
+ rows: number().int().min(1).max(24),
59389
+ buttons: array(RemoteLayoutButtonSchema).max(200)
59390
+ }).superRefine((grid, ctx) => {
59391
+ const ids = /* @__PURE__ */ new Set();
59392
+ const taken = /* @__PURE__ */ new Map();
59393
+ grid.buttons.forEach((button, index) => {
59394
+ if (ids.has(button.id)) ctx.addIssue({
59395
+ code: "custom",
59396
+ message: `button id "${button.id}" is used twice`,
59397
+ path: [
59398
+ "buttons",
59399
+ index,
59400
+ "id"
59401
+ ]
59402
+ });
59403
+ ids.add(button.id);
59404
+ if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
59405
+ ctx.addIssue({
59406
+ code: "custom",
59407
+ message: `button "${button.id}" leaves the grid`,
59408
+ path: ["buttons", index]
59409
+ });
59410
+ return;
59411
+ }
59412
+ for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
59413
+ const cell = `${r}:${c}`;
59414
+ const other = taken.get(cell);
59415
+ if (other !== void 0) {
59416
+ ctx.addIssue({
59417
+ code: "custom",
59418
+ message: `buttons "${other}" and "${button.id}" overlap`,
59419
+ path: ["buttons", index]
59420
+ });
59421
+ return;
59422
+ }
59423
+ taken.set(cell, button.id);
59424
+ }
59425
+ });
59426
+ });
59427
+ var RemoteBoundCommandSchema = object({
59428
+ role: RemoteRoleSchema,
59429
+ /** The operator's name for a custom button; absent for a known role. */
59430
+ label: string().optional(),
59431
+ custom: boolean()
59432
+ });
59433
+ var RemoteCommandListSchema = object({
59434
+ layoutTemplateId: string().nullable(),
59435
+ power: object({ mode: RemotePowerModeSchema }),
59436
+ /** Only the roles that are BOUND — the ones a press can reach. */
59437
+ commands: array(RemoteBoundCommandSchema)
59438
+ });
59439
+ var RemoteRefusalReasonSchema = _enum([
59440
+ "no-remote",
59441
+ "unbound-role",
59442
+ "action-failed"
59443
+ ]);
59444
+ var RemoteSendResultSchema = discriminatedUnion("status", [
59445
+ object({
59446
+ status: literal("sent"),
59447
+ /** How many times the action ran. */
59448
+ sends: number().int().min(1)
59449
+ }),
59450
+ object({
59451
+ status: literal("skipped"),
59452
+ reason: literal("already-in-state")
59453
+ }),
59454
+ object({
59455
+ status: literal("refused"),
59456
+ reason: RemoteRefusalReasonSchema,
59457
+ detail: string().optional()
59458
+ })
59459
+ ]);
59460
+ var RemoteMediaCommandSchema = _enum([
59461
+ "play",
59462
+ "pause",
59463
+ "stop",
59464
+ "next",
59465
+ "previous",
59466
+ "setMute",
59467
+ "selectSource"
59468
+ ]);
59469
+ /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
59470
+ var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
59471
+ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
59472
+ status: literal("refused"),
59473
+ reason: _enum(["unknown-template", "not-a-media-player"]),
59474
+ detail: string()
59475
+ })]);
59476
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
59477
+ DeviceType.MediaPlayer;
59478
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
59479
+ kind: "mutation",
59480
+ auth: "admin"
59481
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
59482
+ role: RemoteRoleSchema,
59483
+ /** Sends in a row (volume steps). */
59484
+ repeat: number().int().min(1).max(50).default(1)
59485
+ }), RemoteSendResultSchema, {
59486
+ kind: "mutation",
59487
+ auth: "protected"
59488
+ }), method(deviceInput.extend({
59489
+ command: RemoteMediaCommandSchema,
59490
+ muted: boolean().optional(),
59491
+ source: string().optional(),
59492
+ repeat: number().int().min(1).max(50).default(1)
59493
+ }), RemoteMediaCommandResultSchema, {
59494
+ kind: "mutation",
59495
+ auth: "protected"
59496
+ });
59497
+ var TemplateKindSchema = _enum(["remote"]);
59498
+ /**
59499
+ * template — the generic store of reusable, named operator data (D963). A
59500
+ * record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
59501
+ * button grid of a remote) and the schema each payload must satisfy are
59502
+ * declared by the system in `template-kinds.ts`. Nothing here is specific to a
59503
+ * kind: the engine validates a payload against its kind's schema and, on a
59504
+ * delete, asks the kind's owner whether anything still points at the record.
59505
+ *
59506
+ * Every refusal is a typed result — a UI says "unknown kind" or names the
59507
+ * devices that still use a template, without parsing text.
59508
+ */
59509
+ var TemplateRecordSchema = object({
59510
+ id: string().min(1),
59511
+ kind: TemplateKindSchema,
59512
+ name: string().min(1).max(120),
59513
+ /** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
59514
+ payload: unknown(),
59515
+ createdAt: number(),
59516
+ updatedAt: number()
59517
+ });
59518
+ var TemplateWriteResultSchema = discriminatedUnion("status", [object({
59519
+ status: literal("saved"),
59520
+ template: TemplateRecordSchema
59521
+ }), object({
59522
+ status: literal("refused"),
59523
+ reason: _enum(["invalid-payload", "not-found"]),
59524
+ detail: string()
59525
+ })]);
59526
+ /** A device still pointing at a template. */
59527
+ var TemplateUserSchema = object({
59528
+ deviceId: number().int().nonnegative(),
59529
+ name: string()
59530
+ });
59531
+ var TemplateDeleteResultSchema = discriminatedUnion("status", [
59532
+ object({ status: literal("deleted") }),
59533
+ object({ status: literal("not-found") }),
59534
+ object({
59535
+ status: literal("in-use"),
59536
+ devices: array(TemplateUserSchema).min(1)
59537
+ })
59538
+ ]);
59539
+ method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
59540
+ kind: TemplateKindSchema,
59541
+ name: string().min(1).max(120),
59542
+ payload: unknown()
59543
+ }), TemplateWriteResultSchema, {
59544
+ kind: "mutation",
59545
+ auth: "admin"
59546
+ }), method(object({
59547
+ id: string().min(1),
59548
+ name: string().min(1).max(120).optional(),
59549
+ payload: unknown().optional()
59550
+ }), TemplateWriteResultSchema, {
59551
+ kind: "mutation",
59552
+ auth: "admin"
59553
+ }), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
59554
+ kind: "mutation",
59555
+ auth: "admin"
59556
+ });
59557
+ /**
59215
59558
  * button — device-scoped capability for HA `button.*` / `input_button.*`
59216
59559
  * fire-only actuators. A button entity has no readable state — pressing it
59217
59560
  * triggers an action on the HA side. There is no `status` / `runtimeState`:
@@ -63413,9 +63756,35 @@ var MediaInfoSchema = object({
63413
63756
  /** Optional cover-art / thumbnail URL. */
63414
63757
  imageUrl: string().optional()
63415
63758
  });
63759
+ /**
63760
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
63761
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
63762
+ * tracks what it last SENT; it moves only after a send was accepted, and a
63763
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
63764
+ * guess, never as a reading.
63765
+ */
63766
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
63767
+ /** The fields of a media-player status a driver can only guess. */
63768
+ var MediaPlayerAssumedFieldSchema = _enum([
63769
+ "state",
63770
+ "volumeLevel",
63771
+ "isMuted",
63772
+ "source"
63773
+ ]);
63416
63774
  var MediaPlayerStatusSchema = object({
63417
63775
  /** Playback lifecycle state. */
63418
63776
  state: MediaPlayerStateSchema,
63777
+ /**
63778
+ * Whether the state fields are readings or the driver's own bookkeeping.
63779
+ * A slice written before this field existed parses as `reported`.
63780
+ */
63781
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
63782
+ /**
63783
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
63784
+ * this is not empty; a field not listed here is a reading even then (power
63785
+ * from a running-state source, mute guessed from the last send).
63786
+ */
63787
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
63419
63788
  /** Volume as 0..100 inclusive. Null when the device has no volume
63420
63789
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
63421
63790
  volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -65378,6 +65747,14 @@ var PetFeederStatusSchema = object({
65378
65747
  feedSound: boolean(),
65379
65748
  /** Speaker / prompt volume level (device-scaled integer). */
65380
65749
  volume: number().meta(readingMeta("none")),
65750
+ /** Portion (grams) of the last manual feed sent from a single-hopper
65751
+ * stepper — the default the next manual feed starts from. Persisted per
65752
+ * device by the provider; null until a manual feed has been sent. */
65753
+ lastFeedGrams: gramsPortion.nullable(),
65754
+ /** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
65755
+ lastFeedHopper1: gramsPortion.nullable(),
65756
+ /** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
65757
+ lastFeedHopper2: gramsPortion.nullable(),
65381
65758
  /** Ms epoch when the slice was last refreshed from the cloud. */
65382
65759
  lastFetchedAt: number()
65383
65760
  });
@@ -71423,6 +71800,14 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
71423
71800
  kind: "mutation",
71424
71801
  auth: "admin"
71425
71802
  });
71803
+ discriminatedUnion("kind", [object({
71804
+ kind: literal("raw"),
71805
+ timings: array(number().int()),
71806
+ settings: TransmitSettingsSchema.optional()
71807
+ }), object({
71808
+ kind: literal("pronto"),
71809
+ code: string()
71810
+ })]);
71426
71811
  function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
71427
71812
  if (running === null) return null;
71428
71813
  const prevRunning = previous?.running ?? null;
@@ -71860,7 +72245,7 @@ function tryConvertDelta(value, from, to) {
71860
72245
  return shifted - origin;
71861
72246
  }
71862
72247
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
71863
- 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.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, 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.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.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.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.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
72248
+ 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.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, 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.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.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.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.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;
71864
72249
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
71865
72250
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
71866
72251
  new Set(CAP_NAMES);
@@ -81150,6 +81535,41 @@ Object.freeze({
81150
81535
  access: "create",
81151
81536
  role: "admin"
81152
81537
  },
81538
+ "remote.getConfig": {
81539
+ capName: "remote",
81540
+ capScope: "system",
81541
+ addonId: null,
81542
+ access: "view",
81543
+ role: "admin"
81544
+ },
81545
+ "remote.listCommands": {
81546
+ capName: "remote",
81547
+ capScope: "system",
81548
+ addonId: null,
81549
+ access: "view",
81550
+ role: "admin"
81551
+ },
81552
+ "remote.sendCommand": {
81553
+ capName: "remote",
81554
+ capScope: "system",
81555
+ addonId: null,
81556
+ access: "create",
81557
+ role: "admin"
81558
+ },
81559
+ "remote.sendMediaCommand": {
81560
+ capName: "remote",
81561
+ capScope: "system",
81562
+ addonId: null,
81563
+ access: "create",
81564
+ role: "admin"
81565
+ },
81566
+ "remote.setConfig": {
81567
+ capName: "remote",
81568
+ capScope: "system",
81569
+ addonId: null,
81570
+ access: "create",
81571
+ role: "admin"
81572
+ },
81153
81573
  "runningState.getStatus": {
81154
81574
  capName: "running-state",
81155
81575
  capScope: "device",
@@ -82340,6 +82760,41 @@ Object.freeze({
82340
82760
  access: "view",
82341
82761
  role: "viewer"
82342
82762
  },
82763
+ "template.create": {
82764
+ capName: "template",
82765
+ capScope: "system",
82766
+ addonId: null,
82767
+ access: "create",
82768
+ role: "admin"
82769
+ },
82770
+ "template.delete": {
82771
+ capName: "template",
82772
+ capScope: "system",
82773
+ addonId: null,
82774
+ access: "delete",
82775
+ role: "admin"
82776
+ },
82777
+ "template.get": {
82778
+ capName: "template",
82779
+ capScope: "system",
82780
+ addonId: null,
82781
+ access: "view",
82782
+ role: "admin"
82783
+ },
82784
+ "template.list": {
82785
+ capName: "template",
82786
+ capScope: "system",
82787
+ addonId: null,
82788
+ access: "view",
82789
+ role: "admin"
82790
+ },
82791
+ "template.update": {
82792
+ capName: "template",
82793
+ capScope: "system",
82794
+ addonId: null,
82795
+ access: "create",
82796
+ role: "admin"
82797
+ },
82343
82798
  "terminalSession.adoptLegacyMonitor": {
82344
82799
  capName: "terminal-session",
82345
82800
  capScope: "system",
@@ -87171,6 +87626,7 @@ var SYSTEM_CAP_VOCABULARY = {
87171
87626
  "recording-archive": system(STORAGE),
87172
87627
  "recording-export": system("recording exports — requested from the timeline, not an automation step"),
87173
87628
  records: system(INTERNAL),
87629
+ remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
87174
87630
  "server-management": system(CLUSTER),
87175
87631
  "settings-store": system(INTERNAL),
87176
87632
  "smtp-provider": system(INTERNAL),
@@ -87183,6 +87639,7 @@ var SYSTEM_CAP_VOCABULARY = {
87183
87639
  "storage-provider": system(STORAGE),
87184
87640
  "stream-broker": system(PIPELINE),
87185
87641
  system: system(CLUSTER),
87642
+ template: system("operator-authored templates — edited in their own editor, never actuated"),
87186
87643
  "terminal-session": system(CLUSTER),
87187
87644
  toast: system(UI_PLUMBING),
87188
87645
  training: system(ML),
@@ -89620,6 +90077,31 @@ Object.freeze({
89620
90077
  form: "single",
89621
90078
  optional: true
89622
90079
  }],
90080
+ "remote.getConfig": [{
90081
+ name: "deviceId",
90082
+ form: "single",
90083
+ optional: false
90084
+ }],
90085
+ "remote.listCommands": [{
90086
+ name: "deviceId",
90087
+ form: "single",
90088
+ optional: false
90089
+ }],
90090
+ "remote.sendCommand": [{
90091
+ name: "deviceId",
90092
+ form: "single",
90093
+ optional: false
90094
+ }],
90095
+ "remote.sendMediaCommand": [{
90096
+ name: "deviceId",
90097
+ form: "single",
90098
+ optional: false
90099
+ }],
90100
+ "remote.setConfig": [{
90101
+ name: "deviceId",
90102
+ form: "single",
90103
+ optional: false
90104
+ }],
89623
90105
  "runningState.getStatus": [{
89624
90106
  name: "deviceId",
89625
90107
  form: "single",
@@ -91777,14 +92259,6 @@ function bestLocationMatch(externalName, existing, threshold = .8) {
91777
92259
  String.raw`(?<=^|["'(\s>,\[{])`;
91778
92260
  var MB = 1024 * 1024;
91779
92261
  1024 * MB, 3072 * MB;
91780
- discriminatedUnion("kind", [object({
91781
- kind: literal("raw"),
91782
- timings: array(number().int()),
91783
- settings: TransmitSettingsSchema.optional()
91784
- }), object({
91785
- kind: literal("pronto"),
91786
- code: string()
91787
- })]);
91788
92262
  object({
91789
92263
  manufacturer: string().optional(),
91790
92264
  supportedModels: array(string()).optional(),
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- const require_dist = require("../dist-C_PMvyYa.js");
27
+ const require_dist = require("../dist-BS9DCd76.js");
28
28
  let node_crypto = require("node:crypto");
29
29
  require("node:zlib");
30
30
  let node_fs = require("node:fs");
@@ -3492,6 +3492,10 @@ var CAPS_NOT_EXPORTED = [
3492
3492
  cap: "ir-transmitter",
3493
3493
  reason: "A pulse-train emitter with no state: it is driven by the remote that owns a command table, and a raw send has no meaningful single entity."
3494
3494
  },
3495
+ {
3496
+ cap: "remote",
3497
+ reason: "A named command map sent through a transmitter. Its useful surface for an ecosystem is the `media-player` the same device provides (power, volume, source); the free-form command name has no typed entity. Its state (last command, last send time) is session-only bookkeeping."
3498
+ },
3495
3499
  {
3496
3500
  cap: "group-status",
3497
3501
  reason: "Bookkeeping for a helper group (D944): how many members were included, excluded, or named. The value an operator automates on is the output capability (the temperature, the motion, the watts). These counts are session-only, have no history, and would publish a second entity that never means the reading."
@@ -1,4 +1,4 @@
1
- import { Ft as BaseAddon, Gt as array, Ht as isReadingQuantity, I as consumableFormOf, L as consumableKindOf, Lt as baseUnitOf, O as buildAddonRouteProvider, Qt as string, U as deviceExportCapability, Ut as nodePin, Xt as object, a as COCO_TO_MACRO, c as ConsumableItemSchema, d as FanDirectionSchema, en as unknown, f as HvacModeSchema, i as CAMERA_SWITCH_ORDER, l as ConsumableStatusSchema, m as PLUG_APPLIANCE_TYPES, nn as EventCategory, o as CameraSwitchIdSchema, p as MediaPlayerRepeatSchema, s as ConsumableFormSchema, st as oauthIntegrationCapability, t as AlarmArmModeSchema, v as addonRoutesCapability } from "../dist-CYl0u8cF.mjs";
1
+ import { Ft as BaseAddon, Gt as array, Ht as isReadingQuantity, I as consumableFormOf, L as consumableKindOf, Lt as baseUnitOf, O as buildAddonRouteProvider, Qt as string, U as deviceExportCapability, Ut as nodePin, Xt as object, a as COCO_TO_MACRO, c as ConsumableItemSchema, d as FanDirectionSchema, en as unknown, f as HvacModeSchema, i as CAMERA_SWITCH_ORDER, l as ConsumableStatusSchema, m as PLUG_APPLIANCE_TYPES, nn as EventCategory, o as CameraSwitchIdSchema, p as MediaPlayerRepeatSchema, s as ConsumableFormSchema, st as oauthIntegrationCapability, t as AlarmArmModeSchema, v as addonRoutesCapability } from "../dist-BusXPPvn.mjs";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
3
  import "node:zlib";
4
4
  import "node:fs";
@@ -3457,6 +3457,10 @@ var CAPS_NOT_EXPORTED = [
3457
3457
  cap: "ir-transmitter",
3458
3458
  reason: "A pulse-train emitter with no state: it is driven by the remote that owns a command table, and a raw send has no meaningful single entity."
3459
3459
  },
3460
+ {
3461
+ cap: "remote",
3462
+ reason: "A named command map sent through a transmitter. Its useful surface for an ecosystem is the `media-player` the same device provides (power, volume, source); the free-form command name has no typed entity. Its state (last command, last send time) is session-only bookkeeping."
3463
+ },
3460
3464
  {
3461
3465
  cap: "group-status",
3462
3466
  reason: "Bookkeeping for a helper group (D944): how many members were included, excluded, or named. The value an operator automates on is the output capability (the temperature, the motion, the watts). These counts are session-only, have no history, and would publish a second entity that never means the reading."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.635",
3
+ "version": "1.2.636",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",